
On Fri, 2007-03-16 at 17:49 +0000, Simon Peyton-Jones wrote:
| newtype Put a = Put { | runPut :: (a -> {-# UNPACK #-} !Buffer -> [B.ByteString]) | -> {-# UNPACK #-} !Buffer -> [B.ByteString] | }
Now you are proposing that
data Bar a = MkBar (!a -> a)
means this:
MkBar f = :MkBar (\x. x `seq` f x)
That is, even if the argument to MkBar is a lazy function, when you take a MkBar apart you'll find a strict function.
Right. And then after this semantic change we can do tricks like changing the calling convention of this function so that it takes that strict argument as its unpacked components.
I suppose you can combine the two notations:
data Baz a = MkBaz !(!a -> a) means MkBaz f = f `seq` :MkBaz (\x. x `seq` f x)
I suppose so.
Interesting. Is that what you meant? An undesirable consequence would be that case (MkBar bot) of MkBar f -> f `seq` 0 would return 0, because the MkBar constructor puts a lambda inside. This seems bad. Maybe you can only put a ! inside the function type if you have a bang at the top (like MkBaz).
Hmm, yes I see. Well that seems like a reasonable restriction. In my original example I was using newtype rather than data (which of course is like data with ! on the only component). Afterall, in practise I think the main use of this semantic change will be to take advantage of faster calling conventions and so we'd be perfectly happy with being strict in function itself. Duncan