Simon, I think you're mistaken.

Simon writes:
> 
>       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.

The posted semantics for strict constructors, illustrated by this example
>from the Haskell 1.3 post, is to insert seq.

> data R = R !Int !Int
> 
> R x y = seq x (seq y (makeR x y)) -- just to show the semantics of R

So if we had

        data Age = Age !Int
        foo (Age n) = (n, Age (n+1))

it would translate to

        foo (MakeAge n) = (n, seq MakeAge (n+1))

[makeAge is the "real" constructor of Age]

Now, surely, seq does not evaluate its first argument when the
closure is built, does it?  Not until we evaluate the second component
of the pair is n evaluated.

The other behaviour of strict constructors would worry me since we
would loose referential transparency.

I'm not opposing newtype, but an ordinary datatype with
one constructor with one strict argument is very similar.
The only way to distinguish them (and it is debatable if
this is what you want) is like this

        data T = T !Int
        f (T _) = True

        newtype T' = T' Int
        f' (T' _) = True

Now we get
f undefined ==> undefined
f' undefined ==> True

        -- Lennart


Reply via email to