Alex Jacobson:
> Ooops, I forgot to remove the "and".  Anyway, my point is that 
> 1. it is not logically consistent to treat exceptions as return values
> 2. as an implementation matter it violates laziness to do so

OK, now I follow.  And diagree. ;-)  On your second point first:
I'm not sure what you mean by "violates laziness"; it would be true
to say that adding exceptional return values in a given way might
well reduce the laziness of the program; but this can always be
obviated, given sufficient care.


> > Using error-monad syntax might be a bit more palatable, but amounts to
> > essentially the same thing.  Alternatively, you can define HOFs to
> > "lift" an n-ary function to an exception-propagating equivalent:

> That is what I did with my Exception version 2 syntax.
> The problem is that doing this lifting ends up being non-lazy.

You're right, it alters the strictness of the program.  But one can
recover the original behaviour by delaying/eliminating the pattern-match,
though I again I agree this is a pain.


> You could argue that this problem is an artifact of the Haskell syntax and
> that we could add Exceptions to the Thunk to achieve the desired result
> (treating exceptions as return values).

I don't think I would, though!  (If I understand what you mean by this.)
The "problem" is an artifact of wanting to keep the language referentially
transparent, which a built-in throw/catch scheme of the sort you
suggest would scupper.


> Our intuition is that foo' is commutative.  foo' a b = foo' b a.
> But that turns out not to be true when you have exceptions.

That's true.  And it remains true _however_ one treats exceptions.
There's no way around that in general, I'm afraid, and I'll cite you
assorted papers on Observable Sequentiality if you really want the
grubby details.


> But the real point here is that Exceptions are, by definition, results
> that are outside the domain of the function being evaluated.  Treating
> exceptions as algebraic types may be comforting, but what you are really
> doing in that case is extending the domain of your function

Effectively, yes.  From a domain theory PoV, this is all that one could
possibly ever do, in fact ('error' included).


> -- and there are limits to how far you can go with that.

These being?


> Truly exceptional conditions are those that truly are outside of the
> domain of the function being evaluated. e.g. factorial -1
> The VALUE of (factorial -1) is not an exception.  Neither is the value of
> (factorial (1 `div` 0)).
> When a function is passed bad arguments, it is not meaningful (from a
> functional perspective) to have it return a value.
> The value of a function over arguments outside its domain is undefined.
> When such an event occurs, the logically consistent behavior is to exit
> function evaluation and tell the caller what was wrong with the
> arguments passed (to the extent it is possible to do).

I don't find this argument at all compelling.  If a value is "truly
outside the domain of the function being evaluated", then don't pass
it to it!  This may seem glib, but I do believe that its better SE
practice in general.  If there are exceptional conditions in "the world",
or if determining a sufficient precondition is not practicable, then I
repeat my advice concerning exceptional return values, a necessary evil
though they might be.


> Right now that means using the error function.  I am just saying that
> error isn't really enough for a production quality language.

Agreed.

> Does this make more sense?

It makes perfect sense, but I think that having exceptions as a language
mechanism in Haskell is not realistic or viable, for the reasons I
outlined before.  I don't pretend that the alternatives are trivial,
or even necessarily very pleasant-looking -- just that they're necessary.

Slainte,
Alex.


Reply via email to