X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;ds=sidebyside;f=Data%2FTree.hs;h=5c95f2ab965ca36e187d4a59a66ed9eac026a21b;hb=9fcd4e60afbfe43c62372cd75fd940c2c4294265;hp=c68e66e86a680dd098657ac3a964414ded8b5ef0;hpb=2cd6a935d4b4b0649748790da04821b159fe25d1;p=ghc-base.git diff --git a/Data/Tree.hs b/Data/Tree.hs index c68e66e..5c95f2a 100644 --- a/Data/Tree.hs +++ b/Data/Tree.hs @@ -18,14 +18,25 @@ module Data.Tree( 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) */ @@ -66,6 +77,61 @@ flatten t = squish t [] -- | 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'