Bug in Control.Monad.State

Yitzchak Gale gale at sefer.org
Wed Nov 23 08:14:02 EST 2005

Hi Udo,

I am posting this response here on the libraries list,
because it is relevant to the discussion about whether
State should be lazy or strict by default.

I am also cross-posting to the haskell list, because
I think the topic may be of more general interest.

I wrote:
> > createItems :: RandomGen g => State g [Item]
> > createItems =
> >   liftM catMaybes $ runListT $
> >   flip evalStateT initialState $ runMaybeT $
> >   do
> >     item <- liftRandom $ repeatM randomItem
> >     updateState item
> >     needMoreItems >>= guard
> >     return item
> >   where
> >     liftRandom = lift . lift . lift

Udo Stenzel wrote:
> ...but this is probably broken anyway.  After
> (repeatM randomItem) presumably the state (the
> RandomGen) is _|_, but the type of createItems
> would suggest it is still usable.

No, it works. MaybeT tells ListT when to stop its
iteration. After that, the RandomGen can be used
again elsewhere.

>  I wouldn't do that.  Other than that it's a bit
> hard to see what you're trying to accomplish
> here.

Lazy monads are an important programming paradigm
in practice.

Laziness helps to completely decouple the various
ingredients of the algorithm from each other.
This helps in debugging, and in dividing tasks
among different development teams.

The monadic approach helps makes refactoring easy
(a common complaint against Haskell). For example,
it would be trivial to add exception handling,
or logging.

The algorithm is clearly specified as an iteration
of a series of steps, the way most people would
naturally think of it. Yet the calculation is
completely pure. So a compiler is not required to
follow the steps literally. It can split the
calculation across different threads, processors,
http connections, etc., if it is smart enough.

This is the way industrial software development
should be done. It is clearly far better than
imperative OO.


More information about the Libraries mailing list