
* On Sunday, May 02 2010, Alexander Dunlap wrote:
Of course, there are situations where it is really awkward to not use partial functions, basically because you *know* that an invariant is satisfied and there is no sane course of action if it isn't. To take a contrived example:
f ys = let xs = (1:ys) in last xs
uses the partial function "last". Rewriting it in the "non-partial style" gives
f ys = case (1:ys) of [] -> Nothing xs -> Just (last xs)
but what possible meaning could a caller of the function ascribe to a "Nothing" result? It just means that there is a bug in f, which is what an error would tell you anyway. Of course, this particular function could easily be rewritten in such a way to be total, but I believe there are more complex examples where it is awkward/impossible to do so.
You're just showing how difficult it is to reason about when the use of partial functions is safe: undefined), with your `non-partial style' version, you still leave open the case of (Just undefined), since we cannot convince ourselves that last only fails on empty lists here... One case where Maybe or Either might be less preferable to an exception is for the output of a lexer (ex. alex does this) because it means you can get some tokens without without forcing the whole input, and do some IO based on the results even if there is a mistake in either reading the input from disk or lexing it. But I think this situation of (ab)using lazy IO and exceptions is an oversimplification, and you can find appropriate alternatives such as iteratee which are more explicit about what is going on. -- Adam