
On Sun, Feb 03, 2013 at 11:22:12PM +0000, Ian Lynagh wrote:
On Sun, Feb 03, 2013 at 10:34:04PM +0000, Ben Millwood wrote:
On Fri, Feb 01, 2013 at 05:10:42PM +0000, Ian Lynagh wrote:
The first is suggested by "A bang only really has an effect if it precedes a variable or wild-card pattern" on http://hackage.haskell.org/trac/haskell-prime/wiki/BangPatterns
We could therefore alter the lexical syntax to make strict things into lexems, for example reservedid -> ... | _ | !_ strictvarid -> ! varid etc. This would mean that "f !x" is 2 lexemes, and "f ! x" 3 lexemes, with the former defining the function 'f' and the latter defining the operator '!'.
This has 3 downsides:
* It would require also accepting the more radical proposal of making let strict, as it would no longer be possible to write let ![x,y] = undefined in ()
We really can't make let strict, in my view: its laziness is sort of fundamental. I don't see why the given example necessitates it though: just use case-of in that scenario.
Well, true, that's another option. It's rather unpleasant when you have multiple bindings, as when converted to 'case's, each 'case' requires you to indent deeper (or to use more braces).
Yes, or you could use a tuple, or you could use seq directly, but I recognise those options as having their own drawbacks. (Observation: if bang patterns are made primitive, seq can be implemented as an ordinary function in terms of them.)
(If we do come up with a way that doesn't involve making ! illegal, maybe we should consider allowing ~ as an operator as well!)
Right, if we went for option 3 then making ~ an operator in the same way as ! would be possible. I think we should be cautious about doing so, though, as it's a semi-one-way change, i.e. once it's an operator and people start using it it becomes a lot trickier to revert the decision.
Yeah, I wouldn't be overeager to do it, just worth remembering that that option becomes open.
Anyway, in light of my above comments, I think I like the first option the best (so bang patterns only apply to variables, let doesn't become strict).
So just to clarify what you're proposing, this wouldn't be valid: let ![x] = e in ... and I guess these wouldn't either?: let !x = e in ... let [!x] = e in ... let (x, ~(y, !z)) = e in ... but these would?: let f !x = e in ... case x of ~(y, !z) -> ()
I have two proposals, I suppose: - make bang patterns operate only on variables and wildcards - make bang patterns in let altogether invalid (with an optional third, "make bang patterns something else entirely") with the justification for the first being that it is the most common case and interferes less with the infix operator !, and the justification for the second being the somewhat weedier general notion that I think unused let bindings should be discardable, and that I think bang-lets confuse the distinction between case and let (but then, arguably ~ already does that). So, my proposal is the following definitely ARE allowed:
let f !x = e in ... case x of ~(y, !z) -> ()
The following definitely AREN'T:
let ![x] = e in ... do ![x] <- e; ...
but the following are allowed by the first proposal but disallowed by the second:
let !x = e in ... let [!x] = e in ... let (x, ~(y, !z)) = e in ... do !x <- e; ... do [!x] <- e; ... do (x, ~(y, !z)) <- e; ...
I'm not committed to this plan. I can see especially why the second pattern on my forbidden list might be useful. But I don't like making operator-! special. (I still think types might be the right place to put this information). Thanks, Ben