Bug in Control.Monad.State

Yitzchak Gale gale at sefer.org
Tue Nov 22 17:48:40 EST 2005


Hi Udo,

> > Lack of laziness is also a serious problem
> > that a user cannot avoid. In my case, I have
> > to completely rewrite StateT, otherwise it is
> > totally unusable.  This is definitely a bug.

> I disagree. If an operation is lazy, there is
> absolutely nothing you as a user can to to
> change that.

Right. Well, you can rewrite the library, or you
can restructure your entire app, but neither of
those are very good options.

> If an operation is too strict...  you can always
> wrap the offending data in another constructor.

I have seen this claim several times, but I am
not yet convinced.

In my case, the unwanted strictness is coming from
the bind method of a monad from the standard
libraries. I don't see how to get rid of that
strictness by wrapping something in a constructor.

And even when it is possible to reduce strictness
by wrapping something - it means changing the
interface of existing functions. In a large
application, that could be a major disaster.

Here is an example. How would you fix this by
wrapping something in a constructor?  No
restructuring is allowed (this is one function in
a large application, so changing the interface of
any function could have major consequences), and
no rewriting libraries is allowed.

You need to construct a random list of items. you
do not know in advance how many I will need; that
is determined by a stateful calculation as you
construct the items. Here is the function; it
diverges, unless you rewrite StateT with
strictness removed:

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

Regards,
Yitz


More information about the Libraries mailing list