Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

That's definitely a stage of a Haskell program design. The stack helps to separate out layers of effects, but it can be easy to fix that stack concretely at an early stage and then feel the weight of it later on with overly specialized functions.

The solution is usually to use the mtl-style transformer classes which let you write generalized functions which depend upon capabilities of the transformer stack instead of the concrete stack itself. You end up with a sort of natural dependency injection framework. For instance, here's a function which works on any RW-style monad stack

    augment :: (MonadReader a m, MonadWriter a m) => a -> m ()
    augment a = ask >>= \a' -> tell (a' <> a)
where the Monoid constraint allowing us to use (<>) is coming from the typeclass Prolog involved with the MonadWriter class.

You can then use augment in ANY monad transformer stack which involves Reader and Writer over the same state type.

Note that this defers the extremely important decision about your monad transformer layer order---the caller of augment decides whether to call it with "ReaderT w (Writer w) a" or "WriterT w (Reader w) a". Reader/Writer commute so it's not a problem, but this changes things in the op's example using "ParsecT (LogicT m)" versus "LogicT (ParsecT m)". If your function depends on a particular ordering of the effects then it must have a less general type.



For maximum modularity, you can combine this with functions like "zoom" and "magnify" of module Control.Lens.Zoom. They let you convert stateful operations that work on a fragment of the global state/environment into operations that work with the whole state/environment (provided that you have the appropriate lenses.) Very useful in complex monad stacks.


s/Prolog/Monoid/


I meant the Prolog-like inference where MonadWriter w m implies Monoid w.


I see. That was a bit obscure, though.


Ah, sorry, I was accidentally writing in the context of another comment I wrote in this thread where I talked about the typeclass resolution machinery. Without that context, it is pretty out of place.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: