spectacle-1.0.0: src/Data/Functor/Tree.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeFamilies #-}
-- |
--
-- @since 0.1.0.0
module Data.Functor.Tree
( -- * Rose Trees
Tree (Node),
rootOf,
leavesOf,
-- ** Construction
pattern (:-),
pattern Leaf,
-- ** Destruction
flatten,
-- ** Maps
mapWithRoot,
-- ** Folds
breadth,
mergeWith,
mergeS,
levels,
)
where
import Control.Applicative (Applicative (liftA2))
import Control.Applicative.Queue (later, now, runQueue)
import Data.Tree (Tree (Node), flatten)
infixr 5 :-
-- ---------------------------------------------------------------------------------------------------------------------
pattern (:-) :: a -> [Tree a] -> Tree a
pattern x :- xs = Node x xs
pattern Leaf :: a -> Tree a
pattern Leaf x = x :- []
{-# COMPLETE (:-) #-}
rootOf :: Tree a -> a
rootOf (x :- _) = x
leavesOf :: Tree a -> [Tree a]
leavesOf (_ :- xs) = xs
-- | @'mapWithRoot' f g ts@ maps each element with @g@ given the immediate root above the current element and that
-- element. @f@ is used for the root of the tree since it has no element above itself.
--
-- @since 0.1.0.0
mapWithRoot :: (a -> b) -> (a -> a -> b) -> Tree a -> Tree b
mapWithRoot f g (t0 :- ts0) = f t0 :- map (go t0) ts0
where
go root (t :- ts) = g root t :- map (go t) ts
breadth :: Applicative f => (a -> f b) -> Tree a -> f (Tree b)
breadth f = runQueue . go
where
go (t :- ts) = liftA2 (:-) (now (f t)) (later (traverse go ts))
levels :: Tree a -> [[a]]
levels ts = go ts []
where
go (x :- xs) (q : qs) = (x : q) : foldr go qs xs
go (x :- xs) [] = [x] : foldr go [] xs
-- | 'mergeWith' is a zip over trees that does not truncate larger subtrees.
--
-- @since 0.1.0.0
mergeWith :: (a -> a -> a) -> Tree a -> Tree a -> Tree a
mergeWith f (Leaf x) (y :- ys) = f x y :- ys
mergeWith f (x :- xs) (Leaf y) = f x y :- xs
mergeWith f (x :- xs) (y :- ys) = f x y :- zipWith (mergeWith f) xs ys
mergeS :: Semigroup a => Tree a -> Tree a -> Tree a
mergeS = mergeWith (<>)