Can there be mtl-like mechanism for monad transformers created by FreeT / ProgramT ?
My understanding of the history is as follows. Once upon a time monad transformer was invented. Then people started to stack monad transformers one on other, then found it annoying to insert lift
everywhere. Then a couple of people invented monad classes, so that we can e.g. ask :: m r
in any monad m
such that MonadReader r m
. This was possible by making every monad class penetrate every monad transformer, like
(Monoid w, MonadState s m) => MonadState s (WriterT w m)
MonadWriter w m => MonadWriter w (StateT s m)
you need such pair of instance declarations for every pair of monad transformers, so when there's n monad transformers there's n^2 costs. This was not a large problem, however, because people will mostly use predefined monads and rarely create their own. The story so far I understand, and also is detailed e.g. in the following Q&A:
Avoiding lift with Monad Transformers
Then my problem is with the new Free monads http://hackage.haskell.org/package/free and Operational monads http://hackage.haskell.org/package/operational . They allow us to write our own DSL and use it as monads, just by defining the language as some algebraic data
type (Operational doesn't even need Functor
instances). Good news is that we can have monads and monad transformers for free; then how about monad classes? Bad news is that the assumption "we rarely define our own monad transformers" no longer holds.
As an attempt to understand this problem, I made two ProgramT
s and made them penetrate each other;
https://github.com/nushio3/practice/blob/master/operational/exe-src/test-05.hs
The operational
package does not support monad classes so I took another implementation minioperational
and modified it to work as I need; https://github.com/nushio3/minioperational
Still, I needed the specialized instance declaration
instance (Monad m, Operational ILang m) => Operational ILang (ProgramT SLang m) where
because the general declaration of the following form leads to undecidable instances.
instance (Monad m, Operational f m) => Operational f (ProgramT g m) where
My question is that how can we make it easier to let our Operational monads penetrate each other. Or, is my wish to have penetration for any Operational monad ill-posed.
I'd also like to know the correct technical term for penetration :)