[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Pattern guards.



Original-Via: uk.ac.nsf; Tue, 9 Oct 90 02:42:08 BST
Date: Mon, 8 Oct 90 21:37:01 EDT
From: Paul Hudak <hudak-paul@cs.yale.edu>
To: haskell@cs.yale.edu
Cc: 
In-Reply-To: Kent Karlsson's message of Mon, 8 Oct 90 17:39:52 +0100 <>
Subject: Pattern guards.
Sender: haskell-request@cs.glasgow.ac.uk

Kent --

All of your points about pattern guards are reasonable, but quite
arguable.  In fact the committee argued over all of them ad nauseum at
least a year ago.  At this point I doubt that Haskell will change to
accommodate more expressive guards, but it is certainly a topic worth
pursuing for Haskell 2.  I suppose that's what you're doing?

A few trailing comments below.

-Paul


      The report does not say whether duplicate identifiers in patterns
   are allowed or not, 

The Report says clearly that they are NOT allowed -- patterns must be
"linear".

      Making things smaller does *not* necessarily make it simpler.
   (Otherwise we would probably write our programs as bit-patterns in
   some standardized machine code... :-)  The system must have integrity
   for it to have simplicity.  If you make cutaways that destroy the
   integrity, then the result will inevitably be complicated.

Lots of philosophy here...:-)

OK, here's a nice simple property:

   Argument order may always be changed without changing the scope of ids.

This property holds under the current proposal, but not under yours.
Seems a shame.

   > than to keep things simple, the chief objection being the following:
   >   x = 1
   >   f y | (x>1) x = x+y
   > Does the x in the guard refer to f's formal parameter or the outer x?

   It cannot possibly refer to f's second formal parameter, it has not been
   bound yet!  

yes, by YOUR definition of "bound".

   It can refer to the outer x, or it can (better yet) be illegal.
   This is perhaps a bit clearer when using another example:
	     f y | (x>1)   (SOME_CONSTRUCTOR x) = x+y
   The pattern for the second argument must not be matched before the
   evaluation of the guard ...

Why not?  (I'm not saying it should, just asking for the rationale
behind your decision.)  For example, consider:

  f ~(SOME_CONSTRUCTOR x) | x>1 = ...

Here the match was "lazy" but the guard forced it to be "strict" -- so
already one must understand the subtleties of what gets matched when.

      In general a guard can only depend upon things that are bound where
   the guard occurs.

Of course; but again I ask: by what definition of bound?

   This would hold also if there is a where-definition
   attached to the clause ((as opposed to just the expression...)).  So, in
	   g  x | (G1)  y | (G2) = ...
	   where   z1 = ...y...
		   z2 = ...x... -- no occurence of y, nor of z1
   z1 may not occur in G1

Why not?  Are you proposing that a static error should result?

   (since y is still unbound; *of course* it should *not* refer 
   to an outer y), 

Why not?  

   but it may occur in G2 (since y has then been bound).
   z2 may occur in both G1 and G2 though.

Your proposal is sounding more and more complex every minute.
It was for reasons such as these that we chose the current design.

(Hopefully it's clear that I'm just playing devil's advocate here:
tell me what the binding rules are, and convince me that they are
simple enough for the neophite.  If you succeed I may support the
proposal for Haskell 2.)

  -Paul