I personally feel that the inclusion of 'fail' in the Monad class is an ugly solution to the problem of pattern matching, and gives the incorrect impression that monads should have some builtin notion of failure. Indeed, it's becoming common to type the result of some function in an arbitrary monad in order to indicate the potential for failure, which is strictly speaking, not the right thing to do. (In a lot of cases, it's going to be no better than complete program failure)
We ought to be using MonadZero when we want to express failure, but it's gone! What do people think of the following proposal? Remove fail from the Monad class. Reinstate MonadZero as a separate class as in Haskell 1.4. Do notation is translated as in Haskell 1.4: do {e} = e do {e;stmts} = e >> do {stmts} -- if p is refutable, do {p <- e; stmts} = let ok p = do {stmts}; ok _ = mzero in e >>= ok -- if p is irrefutable, do {p <- e; stmts} = e >>= \p -> do {stmts} do {let decls; stmts} = let decls in do {stmts} Thus, refutable pattern matches occuring in a do-expression would force the expression to be typed explicitly with MonadZero. This is probably a good thing, as it forces one to think about the consequences of not properly dealing with a pattern match in any monad which doesn't explicitly allow for failure. Even if this translation of do-syntax isn't accepted, I still think that we should have a separate MonadZero. Its existence lets various type signatures become more expressive. There are a lot of cases where a MonadPlus constraint pops up where a MonadZero constraint would do. (I've also been seeing Monad get used for these cases, when it shouldn't!) This distinction allows one to see immediately when a monad is getting used for failure or whether choice is really essential. I'd also like to see the current use of MonadPlus split into MonadElse (or MonadOr) and MonadPlus, as described at the bottom of http://www.haskell.org/hawiki/MonadPlus as it helps to clarify the distinction between backtracking-type failure and immediate failure in types. We could even put this distinction to good use in many monads which do support backtracking anyway: instance MonadElse [] where [] `morelse` ys = ys (x:xs) `morelse` ys = (x:xs) Lastly, it would be nice to have some standard name for the function: option :: (MonadPlus m) => [a] -> m a option = foldr (mplus . return) mzero which seems to come up quite a bit in my experience with nondet monads. - Cale P.S. Oh, and don't get me started about the whole Functor subclass thing, and the inclusion of join in the Monad class. Of course I want those too. :) P.P.S. This reopens the possibility for monad comprehensions, and the more general versions of filter, concat, etc. in the 1.4 prelude -- I wasn't actually around for Haskell 1.4, but I *really* think they'd be a nice language feature to have, as I like to view monads as an abstraction of *containers*, which that syntax/methodology emphasises. I usually find that initially teaching monads to newcomers in terms of containers is much more effective, and that syntax would allow for a nice segue from lists to monads. If people think the error messages are scary, we could provide a switch -fbeginner and a more 98-like prelude to turn monad comprehensions and any other potentially scary features off for the newcomers. _______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell