
John Hughes wrote:
* ! on the left hand side of a let or where *has a different meaning to ! in a pattern* -- it means that the ~ that would have been implicitly inserted by the previous rule, is not inserted after all!
I wish it were that simple, but I don't think it is. let { !x = const undefined y ; !y = const 'a' x } in y desugars in the current proposal to let { x = const undefined y ; y = const 'a' x } in x `seq` y `seq` y which is _|_, but absent implicit ~, let { x = const undefined y ; y = const 'a' x } in y had better (and does) mean 'a'. It's also not that case that !x has the same meaning in both proposals, e.g. let { !x = y ; !y = const 'a' x } in x means 'a' in the current proposal but _|_ in yours. My experience is that "top-level" strictness information has a very different nature from "nested" strictness information, and it's not generally possible to find a single interpretation that covers both. The reason is that strictness is a relationship between a value and its continuation (i.e. context). Nested strictness annotations connect data to a datatype context; top-level strictness annotations in this case connect data to either a case context or a let context. Each of the three situations has to be considered separately.
This is not the same as banging the pattern with the implicit ~, because as I remarked above, !~p is not the same as p.
Actually if ! patterns were handled consistently in let they would come out as ~!p = ~p, so the ! would have no effect. The current proposal effectively borrows the ! notation, which would otherwise be useless, for a different purpose in this case. -- Ben