One proposal currently circulating is that Haskell support both lifted 
and unlifted products.  For example, we could define

>  type    Lifted   = Lifted   Int Int
>  newtype Unlifted = Unlifted Int Int

and

>  f (Lifted x y)   = 3
>  g (Unlifted x y) = 3

Now we have
    f (Lifted _|_  _|_) = g (Unlifted _|_  _|_) = 3
which seems reasonable enough.

On the other hand,
    f _|_ = _|_
    g _|_ =  3
This doesn't really have anything to do with lifted or unlifted 
products!  These last two equations say f is strict and g is not!  If we 
are to be consistent, and require that functions defined using pattern 
matching the way f does are strict, then we should also require that g 
be strict.  (If we look at the definitions of f and g without the type 
definitions in front of us, there is nothing to indicate that one is 
strict and the other isn't.)  With unlifted domains, of course, this 
means that x and y must be evaluated concurrently until at least one 
produces and integer.  In think we can all agree that this is a dump 
idea.

I have not completely made up my mind on the best solution to this 
problem, but have a couple of ideas I would like to suggest for 
consideration.

One solution is to regard algebraic data types as lifted sums of 
unlifted products, except that a type with only one constructor is just 
an unlifted product.  Operationally this seems reasonable, since a 
constructor need only be checked when pattern matching is done if there 
is more than one possible constructor for the type.

Another solution, which generalizes an earlier proposal of mine for 
strictness annotations, is as follows.  We allow lifted, unlifted and 
smash products.  (In a smash product, if any component of a product is 
_|_ then the entire product is bottom.  That is, a smash product 
constructor is strict in every component.)

Consider

>  type Lifted   = Lifted Int Int
>  type Unlifted = ~Unlifted Int Int
>  type Smash    = !Smash Int Int

where the notation "~" indicates an unlifted product and "!" indicates a 
smash product.

The "~" prefix must be used with any unlifted product constructor when 
it is used in a pattern.  For example, with

>  f (Lifted x y)    = 3
>  g (~Unlifted x y) = 3

it is clear that f and g are different.  In particular, it is clear that 
f is strict but g may not be.

The "!" prefix must be used with any smash product constructor when it 
is used in an expression, but may not be used when the constructor is 
used in a pattern.

For example, with

>  h (Smash x y) = 3
>  z = !Smash expa expb

the use of ! in the definition of z clearly indicates that some 
evaluation is performed, and that z is _|_ if either expa or expb is 
_|_.  On the other hand, the use of "!" is prohibited in the definition 
of h.

If we had written

>  h (!Smash x y) = 3  -- WRONG!
>  x = 4
>  y = error "bottom"
>  w = h (!Smash x y)

it would certainly look like w should be 3.  The fact that we must write

>  h (Smash x y) = 3

makes the expression and pattern a bit different, which is appropriate 
in this case.

Clearly every argument of a smash product must be in class Data, and no 
unlifted product or unlifted function can be in class Data.  Lifted and 
smash products can be mixed in an algebraic data type, but an algebraic 
data type with an unlifted product constructor can have only one 
constructor.

Phil Walder would like tuples to be unlifted.  I see no problem with 
this.  Furthermore, I see no need to include an "~" with tuples, since 
the tuple constructor is clearly different from an algebraic data type 
constructor.

Should we use the "~" in expressions as well as patterns?  I don't know.  
What do you think?

In many ways this is a minimal change to Haskell 1.2.  The unlifted 
product almost exists.  Adding the "~" in the algebraic data type 
definition simply tells the compiler that "~" must be used whenever the 
constructor is used in the pattern.  We can use unlifted products now 
except that the compiler won't prevent us from cheating and sometimes 
using an unlifted product as a lifted product.  If we are going to have 
strictness at all, something needs to be added to the language, and this 
approach combines the two concepts in a consistent proposal.

Warren Burton
Simon Fraser University

Reply via email to