I would rather tell someone that to define a new type exactly
isomorphic to an old type they need to write
newtype Type = Constructor typeexp
then tell them that they need to write
data Type = Constructor !typeexp
The latter smacks too much of magic. This is clearly a matter of
taste, where reasonable people may disagree; I'm just putting forward
my preference.
Actually I agree, but I'd like the more general capability as well.
We then just need to decide whether the syntax above is justifiable
shorthand for that special situation.
Paul's suggestion that ! annotations in the type should change the
meaning of a value worries me. It is bound to make reasoning more
difficult. Paul, do you have a formal specification of how the type
annotations should affect the semantics?
I would propose first that the ! annotation can only be applied at
the outermost level (i.e. a -> !b -> c is OK, a -> (a->!b) -> c is
not OK). I presume that LML places a similar constraint on data
constructor annotations.
Equationally the rest seems obvious; if a function f has type
t1 -> !t2 -> t3, its semantics is modified so that:
f x _|_ y = _|_
I think it's straightforward to express this as an "expansion" of
f's definition in terms of "strict".
It would be more in the
spirit of Haskell to require annotations in the function definition,
from which the annotations in the type can be inferred.
Yeah, this would be OK; it is a matter of taste. One could do:
f x !y z = ...
(I should also point out an elegant, but otherwise horrible solution:
have variables DEFAULT to being strict, and require a ~ if you want
one to be lazy -- this eliminates the need for ! altogether, and
actually makes the use of ~ more consistent, but of course it will
cause most programs to have 10 gazillion ~'s (!) :-)
-Paul