Phil writes:
| By the way, with `newtype', what is the intended meaning of
|
| case undefined of Foo _ -> True ?
|
| I cannot tell from the summary on the WWW page. Defining `newtype'
| in terms of `datatype' and strictness avoids any ambiguity here.
|
| Make newtype equivalent to a datatype with one strict constructor.
| Smaller language, more equivalences, simpler semantics, simpler
| implementation. An all around win!
I believe it would be a mistake to do this! Consider:
newtype Age = Age Int
foo :: Age -> (Int, Age)
foo (Age n) = (n, Age (n+1))
Now, we intend that a value of type (Age Int) should be represented by
an Int. Thus, apart from the types involved, the following program should
be equivalent:
type Age' = Int
foo' :: Age' -> (Int, Age')
foo' n = (n, n+1)
So is foo' strict in n? No, it isn't. What about foo? If newtype is just a
strict data constructor, then it *is* strict in n.
Here's what I wrote a little while ago:
"This all very well, but it needs a more formal treatment. As it happens, I
don't think it's difficult. In the rules for case expressions (Fig 3 & 4 in
the 1.2 report) we need to say that the *dynamic* semantics of
case e of { K v -> e1; _ -> e2 }
is
let v = e in e1
if K is the constructor of a "newtype" declaration.
(Of course this translation breaks the static semantics.)
Similarly, the dynamic semantics of (K e) is just that of "e", if
K is the constructor of a "newtype" decl."
Does that make the semantics clear, Phil?
Simon