I'm attempting to define an abstract syntax type using ekmett's libraries bound and free. I have something working, which I can strip down to the following minimal example:
{-# LANGUAGE DeriveFunctor #-}
import Bound
import Control.Monad.Free
type Id = String
data TermF f α =
AppF α α
| BindF Id (Scope () f α)
deriving Functor
newtype Term' α = T {unT :: Free (TermF Term) α}
type Term = Free (TermF Term')
Those last two lines are, uh, not what I was hoping for. They make it kind of a PITA to actually exploit the open recursion for annotations (or whatever).
Is there a better way of using these two libraries together, and/or should I just give up on trying to make Term a free monad?
Make it simple
You can simplify the last two lines into.
This should help you know to consistently use
TandunTeverywhere instead of only at every other level.Make it complicated
Both
FreeandTermFhave the kind(*->*)->(*->*), which is the kind of a transformer. You are looking for the fixed point of the composition ofFreeandTermF. We can write the composition of transformers in general.We can also write the fixed point of transformers in general.
Then you could write
Then use
FixT . ComposeTeverywhere you would have just usedTandunComposeT . unFixTeverywhere you would have usedunT.