X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=Data%2FTree.hs;h=5c95f2ab965ca36e187d4a59a66ed9eac026a21b;hb=e9e2a5412bb7cda8d13a063ac403d9f18ac97380;hp=2ba7b1ab0618e04a7eaf7db0d9f81ece1b147617;hpb=715c78df1e7cdd474926cd919f4193fa9d23ab5e;p=ghc-base.git diff --git a/Data/Tree.hs b/Data/Tree.hs index 2ba7b1a..5c95f2a 100644 --- a/Data/Tree.hs +++ b/Data/Tree.hs @@ -14,16 +14,29 @@ module Data.Tree( Tree(..), Forest, + -- * Two-dimensional drawing drawTree, drawForest, + -- * Extraction flatten, levels, + -- * Building trees + unfoldTree, unfoldForest, + unfoldTreeM, unfoldForestM, + unfoldTreeM_BF, unfoldForestM_BF, ) where #ifdef __HADDOCK__ import Prelude #endif +import Control.Monad +import Data.Maybe +import Data.Queue + -- | Multi-way trees, also known as /rose trees/. -data Tree a = Node a (Forest a) -- ^ a value and zero or more child trees. +data Tree a = Node { + rootLabel :: a, -- ^ label value + subForest :: Forest a -- ^ zero or more child trees + } #ifndef __HADDOCK__ deriving (Eq, Read, Show) #else /* __HADDOCK__ (which can't figure these out by itself) */ @@ -40,38 +53,85 @@ mapTree :: (a -> b) -> (Tree a -> Tree b) mapTree f (Node x ts) = Node (f x) (map (mapTree f) ts) -- | Neat 2-dimensional drawing of a tree. -drawTree :: Show a => Tree a -> String -drawTree = unlines . draw . mapTree show +drawTree :: Tree String -> String +drawTree = unlines . draw -- | Neat 2-dimensional drawing of a forest. -drawForest :: Show a => Forest a -> String +drawForest :: Forest String -> String drawForest = unlines . map drawTree draw :: Tree String -> [String] -draw (Node x ts0) = grp this (space (length this)) (stLoop ts0) - where this = s1 ++ x ++ " " - - space n = replicate n ' ' - - stLoop [] = [""] - stLoop [t] = grp s2 " " (draw t) - stLoop (t:ts) = grp s3 s4 (draw t) ++ [s4] ++ rsLoop ts - - rsLoop [] = error "rsLoop:Unexpected empty list." - rsLoop [t] = grp s5 " " (draw t) - rsLoop (t:ts) = grp s6 s4 (draw t) ++ [s4] ++ rsLoop ts +draw (Node x ts0) = x : drawSubTrees ts0 + where drawSubTrees [] = [] + drawSubTrees [t] = + "|" : shift "`- " " " (draw t) + drawSubTrees (t:ts) = + "|" : shift "+- " "| " (draw t) ++ drawSubTrees ts - grp fst0 rst = zipWith (++) (fst0:repeat rst) - - [s1,s2,s3,s4,s5,s6] = ["- ", "--", "-+", " |", " `", " +"] + shift first other = zipWith (++) (first : repeat other) -- | The elements of a tree in pre-order. flatten :: Tree a -> [a] flatten t = squish t [] - where squish (Node x ts) xs = x:foldr squish xs ts + where squish (Node x ts) xs = x:foldr squish xs ts -- | Lists of nodes at each level of the tree. levels :: Tree a -> [[a]] -levels t = map (map root) $ takeWhile (not . null) $ iterate subforest [t] - where root (Node x _) = x - subforest f = [t | Node _ ts <- f, t <- ts] +levels t = map (map rootLabel) $ + takeWhile (not . null) $ + iterate (concatMap subForest) [t] + +-- | Build a tree from a seed value +unfoldTree :: (b -> (a, [b])) -> b -> Tree a +unfoldTree f b = let (a, bs) = f b in Node a (unfoldForest f bs) + +-- | Build a forest from a list of seed values +unfoldForest :: (b -> (a, [b])) -> [b] -> Forest a +unfoldForest f = map (unfoldTree f) + +-- | Monadic tree builder, in depth-first order +unfoldTreeM :: Monad m => (b -> m (a, [b])) -> b -> m (Tree a) +unfoldTreeM f b = do + (a, bs) <- f b + ts <- unfoldForestM f bs + return (Node a ts) + +-- | Monadic forest builder, in depth-first order +#ifndef __NHC__ +unfoldForestM :: Monad m => (b -> m (a, [b])) -> [b] -> m (Forest a) +#endif +unfoldForestM f = mapM (unfoldTreeM f) + +-- | Monadic tree builder, in breadth-first order, +-- using an algorithm adapted from +-- /Breadth-First Numbering: Lessons from a Small Exercise in Algorithm Design/, +-- by Chris Okasaki, /ICFP'00/. +unfoldTreeM_BF :: Monad m => (b -> m (a, [b])) -> b -> m (Tree a) +unfoldTreeM_BF f b = liftM (fst . fromJust . deQueue) $ + unfoldForestQ f (listToQueue [b]) + +-- | Monadic forest builder, in breadth-first order, +-- using an algorithm adapted from +-- /Breadth-First Numbering: Lessons from a Small Exercise in Algorithm Design/, +-- by Chris Okasaki, /ICFP'00/. +unfoldForestM_BF :: Monad m => (b -> m (a, [b])) -> [b] -> m (Forest a) +unfoldForestM_BF f = liftM (reverseOnto []) . unfoldForestQ f . listToQueue + where reverseOnto :: [a'] -> Queue a' -> [a'] + reverseOnto as q = case deQueue q of + Nothing -> as + Just (a, q') -> reverseOnto (a:as) q' + +-- takes a queue of seeds +-- produces a queue of trees of the same length, but in the reverse order +unfoldForestQ :: Monad m => (b -> m (a, [b])) -> Queue b -> m (Queue (Tree a)) +unfoldForestQ f aQ = case deQueue aQ of + Nothing -> return emptyQueue + Just (a, aQ) -> do + (b, as) <- f a + tQ <- unfoldForestQ f (foldl addToQueue aQ as) + let (ts, tQ') = splitOnto [] as tQ + return (addToQueue tQ' (Node b ts)) + where splitOnto :: [a'] -> [b'] -> Queue a' -> ([a'], Queue a') + splitOnto as [] q = (as, q) + splitOnto as (_:bs) q = case fromJust (deQueue q) of + (a, q') -> splitOnto (a:as) bs q'