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




Reply via email to