Thanks for feedback about pattern guards. Here are some quick responses.
1. Several people have suggested something along the lines of being
able to backtrack half way through a pattern guard. I considered this
but (a) I couldn't see a nice syntax for it and
(b) it's against the spirit of independent guarded equations
Re (b) we write
f (x:xs) [] = e1
f (x:xs) (y:ys) = e2
when you might think we should find a syntax to allow
f (x:xs) [] = e1
(y:ys) = e2
But we write out the common prefix and expect the compiler to spot the
common pattern. Similarly I think we should rely on the compiler to spot
common prefixes of guards.
f x y | (x:xs) <- xs,
[] <- ys
= e1
| (x:xs) <- xs,
(y:ys) <- ys
= e2
The only extra difficulty is that the RHS of the pattern guard can be an
expression.
2. Chris Dornan suggests a second change, adding guarded conditionals.
This makes some sense to me, but it has a lower power-to-weight ratio
(less gain for similar pain) so I think we should consider them separately.
I've not found myself really hating if-then-else enough to want to change it.
3. I think it's quite important to use "<-" rather than "=".
a) it means that the syntax is precisely that of list comprehensions
b) there's an "=" in the definition already, as Andy points out:
simplify (Plus e e') | let (Val 0) = s = s'
| let (Val 0) = s' = s
| otherwise = Plus s s'
where
s = simplify e
s' = simplify e'
now there are too many "=" signs to parse easily.
c) Furthermore, "let" can introduce multiple
mutually-recursive bindings,
and that leads to all the "which order to test" problems
that I outlined earlier.
Point (b) might even suggest disallowing the let form. Under my proposal
I can write this:
foo x | let y = x+1 = y+1
It's a bit silly, because I can also use let or where in this
situation, but it's not ambiguous so I don't see any particularly
good reason to disallow it.
CONCLUSION: "let" should be allowed, but should introduce multiple,
mutually-recursive bindings. If any are pattern bindings then they
are matched lazily, and failure to match is a program error. Exactly
as for ordinary let/where bindings, and let bindings in list
comprehensions.
4. Some people have suggested some monadic generalisations, so that
f g xs | y <- xs = g y
could mean "map g xs". Such generalisations *might* be possible,
but I'm pretty dubious about them. Keep it simple!
Simon