
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. Regards, Yitz