On Mon, 8 Jun 1998, Alex Ferguson wrote:
> > In the backchannel, Alastair Reid and Adrian Hey, have convinced me
> > that the return values of functions and cannot be represented using
> > algebraic types.
> 
> I'm not clear what you mean by this.

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

> 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.

For example, suppose you had:

> x= 1/0 - NaN
> y= fact -1   - infinite loop

> x'=divideOrException 1 0 -- 'Exception DivisionByZero'
> y'=factorialOrException -1 -- 'Exception NotFactorialDomain -1'

Now define:

> foo a b  = 2 -- foo is not strict in its arguments

In normal haskell,

> result = foo x y

result would have value 2.

If divide and factorial are functions that can throw exceptions then,
using my monad-like syntax for Exceptions,

> result= foo << x' <<+ y' -- '<<' converts a function to a wrapper
                           -- '<<+' adds arg w/ different exception type

and the value of result will be Exception DivisionByZero 

So the problem with just using HOF (whatever the syntax) is that x and y
must be evaluated before they can be passed to a function, violating
laziness.

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).  But, that doesn't work either.
For example, suppose that we define a new function:

> foo' a b = a + b -- foo' is strict in its arguments

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.
Take x and y from before,

> z = foo' x' y'

What is the value of z? Haskell does not promise to evaluate arguments in
any particular order so, depending on implementation, z may be either
Exception DivideByZero or Exception NotFactorialDomain -1.  

Another possibiity is that z should be a list of exceptions, but that
doesn't really work either:

> foo'' a b c = if  a + b == c then a+b+c

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 -- and there
are limits to how far you can go with that.

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).

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

Does this make more sense?

-Alex-
___________________________________________________________________
S. Alexander Jacobson                   i2x Media  
1-212-697-0184 voice                    1-212-697-1427 fax



Reply via email to