{-# LANGUAGE Rank2Types #-} ----------------------------------------------------------------------------- -- | -- Module : Control.Monad.Free -- Copyright : 2008 Dan Doel, Edward Kmett -- License : BSD3 -- -- Maintainer : dan.doel@gmail.com -- Stability : experimental -- Portability : non-portable (rank-2 types) -- -- An implementation of the free monad of a functor, used in (at the least) -- futumorphisms and chronomorphisms in Control.Recursion -- ----------------------------------------------------------------------------- module Control.Monad.Free ( Free() , inFree , cataFree , distribFree ) where import Control.Arrow ((|||), (+++), (>>>)) import Control.Applicative import Control.Monad -- | The free monad of a functor 'f', formally, -- -- > Free F A = mu X. A + FX newtype Free f a = Free { unFree :: Either a (f (Free f a)) } instance (Functor f) => Functor (Free f) where fmap f = unFree >>> f +++ fmap (fmap f) >>> Free instance (Functor f) => Applicative (Free f) where pure = return (<*>) = ap instance (Functor f) => Monad (Free f) where return = Free . Left (Free e) >>= f = either f (inFree . fmap (>>= f)) e -- | The catamorphism for the free monad cataFree :: Functor f => (a -> b) -> (f b -> b) -> Free f a -> b cataFree f g = unFree >>> f ||| g . fmap (cataFree f g) inFree :: f (Free f a) -> Free f a inFree = Free . Right -- | Lifts a distributive law of @h@ over @f@ to a distributive -- law of @Free h@ over @f@ distribFree :: (Functor f, Functor h) => (forall a. h (f a) -> f (h a)) -> (forall a. Free h (f a) -> f (Free h a)) distribFree d = cataFree (fmap return) (fmap inFree . d)