Skip to content

Instantly share code, notes, and snippets.

@gallais
Last active December 19, 2017 03:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gallais/4c59b949c743c0a85cab55dcb73aaf7c to your computer and use it in GitHub Desktop.
Save gallais/4c59b949c743c0a85cab55dcb73aaf7c to your computer and use it in GitHub Desktop.
{-# LANGUAGE DeriveFunctor #-}
module MonadTree where
import Control.Monad
import Control.Monad.Fix
newtype Tree m a = Tree { runTree :: m (Node m a) }
deriving (Functor)
data Node m a = Node
{ nodeValue :: a
, nodeChildren :: [Tree m a]
} deriving (Functor)
valueM :: Functor m => Tree m a -> m a
valueM = fmap nodeValue . runTree
childrenM :: Functor m => Tree m a -> m [Tree m a]
childrenM = fmap nodeChildren . runTree
joinTree :: Monad m => m (Tree m a) -> Tree m a
joinTree = Tree . join . fmap runTree
instance Monad m => Applicative (Tree m) where
pure a = Tree $ pure $ Node a []
(<*>) = ap
instance Monad m => Monad (Tree m) where
return = pure
m >>= k =
Tree $ do
Node x xs <- runTree m
Node y ys <- runTree (k x)
pure . Node y $
fmap (>>= k) xs ++ ys
instance Monad m => MonadFix (Tree m) where
mfix f = Tree $ do
shape <- fix $ (pure . f =<<) . (valueM =<<)
node <- runTree shape
let value = nodeValue node
let trees = nodeChildren node
let children = zipWith (\ k _ -> mfix (joinTree . fmap (!! k) . childrenM . f)) [0..] trees
return $ Node value children
@treeowl
Copy link

treeowl commented Dec 19, 2017

Is it okay if I adapt this for use in Data.Tree? I believe in that simpler context it looks like this:

mfixTree :: (a -> Tree a) -> Tree a
mfixTree f
  | Node a children <- fix (f . rootLabel)
  = Node a (zipWith (\i _ -> mfixTree ((!! i) . subForest . f))
                    [0..] children)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment