-- (c) MP-I (1998/9-2006/7) and CP (2005/6-2022/23) module LTree where import Cp import Data.Monoid import Control.Applicative import List -- (1) Datatype definition ----------------------------------------------------- data LTree a = Leaf a | Fork (LTree a, LTree a) deriving (Show, Eq, Ord) inLTree :: Either a (LTree a, LTree a) -> LTree a inLTree = either Leaf Fork outLTree :: LTree a -> Either a (LTree a,LTree a) outLTree (Leaf a) = i1 a outLTree (Fork (t1,t2)) = i2 (t1,t2) baseLTree g f = g -|- f >< f -- (2) Ana + cata + hylo ------------------------------------------------------- recLTree f = baseLTree id f -- that is: id -|- (f >< f) cataLTree g = g . (recLTree (cataLTree g)) . outLTree anaLTree f = inLTree . (recLTree (anaLTree f) ) . f hyloLTree f g = cataLTree f . anaLTree g -- (3) Map --------------------------------------------------------------------- instance Functor LTree where fmap f = cataLTree ( inLTree . baseLTree f id ) -- (4) Examples ---------------------------------------------------------------- -- (4.0) Inversion (mirror) ---------------------------------------------------- mirrorLTree = cataLTree (inLTree . (id -|- swap)) -- (4.1) Count and depth ------------------------------------------------------- countLTree = cataLTree (either one add) depth = cataLTree (either one (succ.umax)) -- (4.2) Serialization --------------------------------------------------------- tips = cataLTree (either singl conc) -- (4.3) Double factorial ------------------------------------------------------ dfac 0 = 1 dfac n = hyloLTree (either id mul) dfacd (1,n) dfacd(n,m) | n==m = i1 n | otherwise = i2 ((n,k),(k+1,m)) where k = div (n+m) 2 -- (4.4) Double square function ------------------------------------------------ dsq 0 = 0 dsq n = (cataLTree (either id add) . fmap (\n->2*n-1) . (anaLTree dfacd)) (1,n) {-- dsq 0 = 0 dsq n = (hyloLTree (either id add) (fdfacd nthodd)) (1,n) where nthodd n = 2*n - 1 fdfacd f (n,m) | n==m = i1 (f n) | otherwise = i2 ((n,k),(k+1,m)) where k = div (n+m) 2 --} -- (4.5) Fibonacci ------------------------------------------------------------- fib = hyloLTree (either one add) fibd -- where fibd n | n < 2 = i1 () | otherwise = i2 (n-1,n-2) -- (4.6) Merge sort ------------------------------------------------------------ mSort :: Ord a => [a] -> [a] mSort [] = [] mSort l = hyloLTree (either singl merge) lsplit l --where -- singl x = [x] merge (l,[]) = l merge ([],r) = r merge (x:xs,y:ys) | x < y = x : merge(xs,y:ys) | otherwise = y : merge(x:xs,ys) lsplit [x] = i1 x lsplit l = i2 (sep l) where sep [] = ([],[]) sep (h:t) = let (l,r) = sep t in (h:r,l) -- a List cata {-- pointwise version: mSort :: Ord a => [a] -> [a] mSort [] = [] mSort [x] = [x] mSort l = let (l1,l2) = sep l in merge(mSort l1, mSort l2) --} -- (4.7) Double map (unordered lists) ------------------------------------------ dmap :: (b -> a) -> [b] -> [a] dmap f [] = [] dmap f x = (hyloLTree (either (singl.f) conc) lsplit) x -- (4.8) Double map (keeps the order) ------------------------------------------ dmap1 :: (b -> a) -> [b] -> [a] dmap1 f [] = [] dmap1 f x = (hyloLTree (either (singl.f) conc) divide) x where divide [x] = i1 x divide l = i2 (split (take m) (drop m) l) where m = div (length l) 2 -- (4.8) Combinations ---------------------------------------------------------- comb = hyloLTree (either id add) divide where divide(n,k) = if k `elem` [0,n] then i1 1 else i2((n-1,k),(n-1,k-1)) {-- pointwise: comb (n,k) = if k `elem` [0,n] then 1 else comb(n-1,k)+comb(n-1,k-1) --} -- (5) Monads ------------------------------------------------------------------ instance Monad LTree where return = Leaf t >>= g = (mu . fmap g) t mu :: LTree (LTree a) -> LTree a mu = cataLTree (either id Fork) instance Strong LTree {-- fmap :: (Monad m) => (t -> a) -> m t -> m a fmap f t = do { a <- t ; return (f a) } --} mcataLTree g = k where k (Leaf a) = return(g1 a) k (Fork(x,y)) = do { a <- k x; b <- k y; return(g2(a,b)) } g1 = g . i1 g2 = g . i2 -- (6) Going polytipic ------------------------------------------------------- -- natural transformation from base functor to monoid tnat :: Monoid c => (a -> c) -> Either a (c, c) -> c tnat f = either f (uncurry mappend) -- monoid reduction monLTree f = cataLTree (tnat f) -- alternative to (4.2) serialization ---------------------------------------- tips' = monLTree singl -- alternative to (4.1) counting --------------------------------------------- countLTree' = monLTree (const (Sum 1)) -- distributive law ---------------------------------------------------------- dlLTree :: Strong f => LTree (f a) -> f (LTree a) dlLTree = cataLTree (either (fmap Leaf) (fmap Fork .dstr)) -- (7) Zipper ---------------------------------------------------------------- data Deriv a = Dr Bool (LTree a) type Zipper a = [ Deriv a ] plug :: Zipper a -> LTree a -> LTree a plug [] t = t plug ((Dr False l):z) t = Fork (plug z t,l) plug ((Dr True r):z) t = Fork (r,plug z t) -- (8) Advanced -------------------------------------------------------------- instance Applicative LTree where pure = return (<*>) = aap -- (9) Spine representation -------------------------------------------------- roll = inLTree.(id -|- roll>< id).beta.(id>< id).spineOut spineOut = beta.(id>< id).outLTree alpha :: Either a ((a, t), t1) -> (a, Either () (t1, t)) alpha(Left a) = (a,Left()) alpha(Right ((a,ts),t)) = (a,Right(t,ts)) beta :: (a, Either () (t1, t)) -> Either a ((a, t), t1) beta(a,Left()) = Left a beta(a,Right(t,ts)) = Right ((a,ts),t) height = cataLTree (either id (uncurry ht)) where ht a b = 1 + (max a b) ---------------------------- end of library ----------------------------------