I have a problem to which a stack of monad transformers (or even one monad transformer) over IO. Everything is good, except that using lift before every action is terribly annoying! I suspect there is really nothing to do about that, but I thought I’d ask anyway.
I am aware of lifting entire blocks, but what if the code is really of mixed types? Would it not be nice if GHC threw in some syntactic sugar (for example, <-$ = <- lift)?
For all the standard mtl monads, you don’t need
liftat all.get,put,ask,tell— they all work in any monad with the right transformer somewhere in the stack. The missing piece isIO, and even thereliftIOlifts an arbitrary IO action down an arbitrary number of layers.This is done with typeclasses for each “effect” on offer: for example,
MonadStateprovidesgetandput. If you want to create your ownnewtypewrapper around a transformer stack, you can doderiving (..., MonadState MyState, ...)with theGeneralizedNewtypeDerivingextension, or roll your own instance:You can use this to selectively expose or hide components of your combined transformer, by defining some instances and not others.
(You can easily extend this approach to all-new monadic effects you define yourself, by defining your own typeclass and providing boilerplate instances for the standard transformers, but all-new monads are rare; most of the time, you’ll get by simply composing the standard set offered by mtl.)