The easiest thing for you to do would be to get rid of ErrorT from your stack. If you look here you can see that Happstack defines built-in passthrough instances of FilterMonad for StateT and ReaderT, but none for ErrorT. If you really want to keep ErrorT in your stack, then you need to write a passthrough instance for it. It will probably look a lot like the one for ReaderT.
instance (FilterMonad res m) => FilterMonad res (ReaderT r m) where
setFilter f = lift $ setFilter f
composeFilter = lift . composeFilter
getFilter = mapReaderT getFilter
I tend to think that you shouldn't have ErrorT baked into your application monad because you won't always be dealing with computations that can fail. If you do need to handle failure in a section of your code, you can always drop into it easily just by wrapping runErrorT
around the section and then using ErrorT
, lift
, and return
as needed. Also, extra layer in your transformer stack adds a performance tax on every bind. So while the composability of monad transformers is really nice, you generally want to use them sparingly when performance is a significant consideration.
Also, I would recommend using EitherT instead of ErrorT. That way you can make use of the fantastic errors package. It has a lot of really common convenience functions like hush, just, etc.
Also, if you want to see a real example of what you're trying to do, check out Snap's Handler monad. Your MyApp monad is exactly the problem that snaplets were designed to solve. Handler has some extra complexity because it was designed to solve the problem in a generalized way so that Snap users wouldn't need to build this common transformer stack themselves. But if you look at the underlying implementation you can see that at its core it is really just the Reader and State monads condensed into one.