module Monad.Free where
import qualified Prelude as P
import Data.Constraint
import Data.Proxy
import Data.Tagged
import Category
import Functor
import Coproduct
import Monad
import NatTr
import NatTr.Coproduct
data Free f a where
Free :: FMap f (Free f a) -> Free f a
Pure :: EndoFunctorOf f (->) => a -> Free f a
freeT :: EndoFunctorOf f (->) => NatTr (->) (->) (f :.: Ftag (Free f)) (Ftag (Free f))
freeT = NatTr (Tagged Free)
pureT :: EndoFunctorOf f (->) => NatTr (->) (->) Id (Ftag (Free f))
pureT = NatTr (Tagged Pure)
unfreeT :: forall f. EndoFunctorOf f (->) => NatTr (->) (->) (Ftag (Free f)) ((f :.: Ftag (Free f)) :+: Id)
unfreeT = NatTr (Tagged t) where
t :: forall a. Free f a -> FMap ((f :.: Ftag (Free f)) :+: Id) a
t (Free f) = appNat inj1 f
t (Pure a) = appNat inj2 a
instance EndoFunctorOf f (->) => P.Functor (Free f) where
fmap t = go where
go (Free f) = Free (proxy morphMap (Proxy :: Proxy f) go f)
go (Pure a) = Pure (t a)
instance EndoFunctorOf f (->) => P.Monad (Free f) where
f >>= t = go f where
go (Free x) = Free (proxy morphMap (Proxy :: Proxy f) go x)
go (Pure a) = t a
return = Pure
data FreeM = FreeM
instance Functor FreeM ('KProxy :: KProxy (* -> *)) where
type Domain FreeM = NatTr (->) (->)
type Codomain FreeM = MonadMorph (->)
type FMap FreeM f = Ftag (Free f)
morphMap = Tagged (\t -> case observeObjects t of Dict -> f t) where
f t = MonadMorph go where
go = coproduct (freeT . compNat t go) pureT . unfreeT