[Haskell-cafe] Re: Debugging partial functions by the rules

oleg at pobox.com oleg at pobox.com
Wed Nov 15 03:21:00 EST 2006


Donald Bruce Stewart wrote:
> So all this talk of locating head [] and fromJust failures got me
> thinking:
>
>     Couldn't we just use rewrite rules to rewrite *transparently*
>     all uses of fromJust to safeFromJust, tagging the call site
>     with a location?

I'm sorry for shifting the topic: I'm wondering if, rather than trying
to make an error message more informative, we ought to make sure that
no error will ever arise? 

The fromJust and `head of empty list' errors are totally equivalent to
the dereferencing of zero pointer in C++ or NullPointerException in
Java. It pains me to see that exactly the same problem arises in
Haskell -- keeping in mind that already in C++ and Java one may
exterminate these errors given right encapsulations. Languages like
Cyclone or Cw use the type system to eliminate such errors. Surely
Haskell can do something about this?

This topic has been discussed at length on this list. It seems that
the discussion came to the conclusion that eliminating head of
the empty list error is possible and quite easy in Haskell.

  http://www.haskell.org/pipermail/haskell-cafe/2006-September/017915.html
  http://www.haskell.org/pipermail/haskell-cafe/2006-September/017937.html

As to fromJust: would the world come to an end if this function is
just not available? Oftentimes when we get the value of the type
|Maybe a|, the algorithm prescribes the actions for the case if this
value is Nothing. Thus the function `maybe', the deconstructor, seems
to be called for. And if we are dead sure that the |Maybe a| value
is definitely |Just smth| and we need to extract this |smth|, we
can always write
	maybe (assert False undefined) id value
I like how this phrase stands out in the code, to remind me to
double-check my certainty about the value (and perhaps, to re-factor
the code).

Similarly for empty lists: it is often algorithmically significant as
it is the base case for our recursion/induction. Thus, we have to make
the null check according to the algorithm anyway. The type system can
carry the result of such a test, so we don't have to repeat it. The
functions head and tail should operate on the newtype NonemptyList --
in which case they are total. Other list functions may remain as they
are, because we can always `forget' the NonemptyList tag. The run-time
overhead is zero, the notational overhead is not much: writing a few
extra `fromNonemptyList'. Compare with writing `fromIntegral',
especially in the FFI-related code.

The Haskell type system can do far more complex things, for example,
solve the pervasive SQL injections and cross-site scripting problems:

http://blog.moertel.com/articles/2006/10/18/a-type-based-solution-to-the-strings-problem

(This URL appeared on one of the recent Haskell Weekly News,
btw). Surely we can do something about a far simpler problem of head
[] and fromJust? We may have to adjust our coding styles a
little. The adjustment doesn't appear extensive; besides, isn't the
whole point of programming in Haskell is to think differently?



More information about the Haskell-Cafe mailing list