4 ms·
> It appears that in the presence of mutable state, a lot of the advantages of monads become moot. In the simpler cases where use of monads can be replaced by
by Peaker 13y ago
> It appears that in the presence of mutable state, a lot of the advantages of monads become moot.
In the simpler cases where use of monads can be replaced by simple mutable state -- you still lose out on the explicit types of the mutating vs. pure code.
For example, STM is possible because mutating effects are typed, and so can be ruled out of STM transactions.
And in the more complex monads (e.g: transformer stacks), mutable state is just not good enough. You can compose transformers to build things that mutable state simply cannot express, and you'd have to CPS transform your code and avoid mutable state to express those things.
For example, these two monads:
ListT (ParsecT m)
ParsecT (ListT m)
Have no corresponding "mutable state" representations.
- tel 13y agoThat's a really great point that I rarely see come up. Yes, Haskell makes you "recreate" the RWST monad stack that imitates impure languages... but the same tools also let you build other "language domains" which are fiendishly difficult to implement in non-pure settings (on par with CPS transforming yourself into the mother monad and then working backwards from there). On Lisp has a chapter devoted to making a leaky macro-based CPS transformer for Common List. ContT adds CPS to any monad stack as quickly as newtype ContT r m a = ContT { runContT :: (a -> m r) -> m r }
- jeremyjh 13y ago>Yes, Haskell makes you "recreate" the RWST monad stack that imitates impure languages This is really a point that seems to get lost in most of learning materials on the web. LYAH doesn't even acknowledge transformers. I am pretty new to Haskell but it seems to me that transformer stack decisions are a pretty significant design decision for your application. What has happened to me is almost all the code in my application has wound up inside this stack; the only pure functions are trivial helpers. I'm not aware of what has been written on this topic in terms of guidance or advice. But it seems like it is definitely one of the later-stage humps for a new Haskell developer like me.
- tel 13y agoThat'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.
- danidiaz 13y agoFor 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.
- nandemo 13y agos/Prolog/Monoid/
- tel 13y agoI meant the Prolog-like inference where MonadWriter w m implies Monoid w.