Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I avoid using Monad fail?

Tags:

haskell

monads

I'm fairly new to Haskell and have been slowly getting the idea that there's something wrong with the existence of Monad fail. Real World Haskell warns against its use ("Once again, we recommend that you almost always avoid using fail!"). I just noticed today that Ross Paterson called it "a wart, not a design pattern" back in 2008 (and seemed to get quite some agreement in that thread).

While watching Dr Ralf Lämmel talk on the essence of functional programming, I started to understand a possible tension which may have led to Monad fail. In the lecture, Ralf talks about adding various monadic effects to a base monadic parser (logging, state etc). Many of the effects required changes to the base parser and sometimes the data types used. I figured that the addition of 'fail' to all monads might have been a compromise because 'fail' is so common and you want to avoid changes to the 'base' parser (or whatever) as much as possible. Of course, some kind of 'fail' makes sense for parsers but not always, say, put/get of State or ask/local of Reader.

Let me know if I could be off onto the wrong track.

Should I avoid using Monad fail? What are the alternatives to Monad fail? Are there any alternative monad libraries that do not include this "design wart"? Where can I read more about the history around this design decision?

like image 307
Steven Shaw Avatar asked Nov 17 '11 08:11

Steven Shaw


People also ask

Why do we need monad?

monads are used to address the more general problem of computations (involving state, input/output, backtracking, ...) returning values: they do not solve any input/output-problems directly but rather provide an elegant and flexible abstraction of many solutions to related problems.

What problem do monads solve?

Conclusion. Monad is a simple and powerful design pattern for function composition that helps us to solve very common IT problems such as input/output, exception handling, parsing, concurrency and other.

What is monad in oops?

In terms of OO programming, a monad is an interface (or more likely a mixin), parameterized by a type, with two methods, return and bind that describe: How to inject a value to get a monadic value of that injected value type; How to use a function that makes a monadic value from a non-monadic one, on a monadic value.

Is a monad a data structure?

In functional programming, a monad is a software design pattern with a structure that combines program fragments (functions) and wraps their return values in a type with additional computation.


2 Answers

Some monads have a sensible failure mechanism, e.g. the terminal monad:

data Fail x = Fail 

Some monads don't have a sensible failure mechanism (undefined is not sensible), e.g. the initial monad:

data Return x = Return x 

In that sense, it's clearly a wart to require all monads to have a fail method. If you're writing programs that abstract over monads (Monad m) =>, it's not very healthy to make use of that generic m's fail method. That would result in a function you can instantiate with a monad where fail shouldn't really exist.

I see fewer objections to using fail (especially indirectly, by matching Pat <- computation) when working in a specific monad for which a good fail behaviour has been clearly specified. Such programs would hopefully survive a return to the old discipline where nontrivial pattern matching created a demand for MonadZero instead of just Monad.

One might argue that the better discipline is always to treat failure-cases explicitly. I object to this position on two counts: (1) that the point of monadic programming is to avoid such clutter, and (2) that the current notation for case analysis on the result of a monadic computation is so awful. The next release of SHE will support the notation (also found in other variants)

case <- computation of   Pat_1 -> computation_1   ...   Pat_n -> computation_n 

which might help a little.

But this whole situation is a sorry mess. It's often helpful to characterize monads by the operations which they support. You can see fail, throw, etc as operations supported by some monads but not others. Haskell makes it quite clumsy and expensive to support small localized changes in the set of operations available, introducing new operations by explaining how to handle them in terms of the old ones. If we seriously want to do a neater job here, we need to rethink how catch works, to make it a translator between different local error-handling mechanisms. I often want to bracket a computation which can fail uninformatively (e.g. by pattern match failure) with a handler that adds more contextual information before passing on the error. I can't help feeling that it's sometimes more difficult to do that than it should be.

So, this is a could-do-better issue, but at the very least, use fail only for specific monads which offer a sensible implementation, and handle the 'exceptions' properly.

like image 133
pigworker Avatar answered Oct 14 '22 05:10

pigworker


In Haskell 1.4 (1997) there was no fail. Instead, there was a MonadZero type class which contained a zero method. Now, the do notation used zero to indicate pattern match failure; this caused surprises to people: whether their function needed Monad or MonadZero depended on how they used the do notation in it.

When Haskell 98 was designed a bit later, they did several changes to make programming simpler to the novice. For example, monad comprehensions were turned into list comprehensions. Similarly, to remove the do type class issue, the MonadZero class was removed; for the use of do, the method fail was added to Monad; and for other uses of zero, a mzero method was added to MonadPlus.

There is, I think, a good argument to be made that fail should not be used for anything explicitly; its only intended use is in the translation of the do notation. Nevertheless, I myself am often naughty and use fail explicitly, too.

You can access the original 1.4 and 98 reports here. I'm sure the discussion leading to the change can be found in some email list archives, but I don't have links handy.

like image 28
ibid Avatar answered Oct 14 '22 05:10

ibid