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

Pattern matching, not optional arguments

RPG:  If the strategy is to be able to pass an arbitrary number of arguments,
      then a syntax that binds one variable to all of them following by a
      pretty destructuring bind of some sort is much better than a
      syntax that mixes required with &rest (as Jonathan suggested).

JAR:  I agree.  In my experience, pattern-matching languages seem to have an
      inevitable tendency to become baroque and disgusting.  But let's not
      stop looking for a decent one.

Me too.  Our experience at Indiana is that a relatively simple match
facility goes a long long way.  It does not need to complicate the
rest of the language.  On the contrary, I think it eliminates any
justification for making lambda baroque and disgusting.  Please, let's
make an honest attempt to standardize on a matching facility first,
and only then decide if their is sufficient justification to corrupt
the jewel of Scheme.  Given match, we may even be able to polish our
jewel by relegating the "." rest feature to optional or discarded

To fuel the debate, which I hope will have matured by the time of our
next meeting, here is documentation for a match facility that I've
enjoyed using.

(match <exp> (<pattern> <body> ...) ...)

<pattern> ::= <variable>
	    | <number> | <string> | (quote <object>)
	    | (vector <pattern> ...)
	    | (? <predicate> <pattern>)
	    | (<pattern> ...)
	    | (<pattern> <pattern> ... . <pattern>)

Match is a fairly general pattern matching and destructuring facility.  <exp>
is evaluated and its value is matched against the <pattern>s in order until a
matching pattern is found.  An error is signaled if no pattern matches.  When
a match is found, the value of <exp> is destructured with the variables in
the matching pattern bound to the corresponding components of <exp>'s value.
The <body> expressions of the matching pair are then evaluated in an
environment formed by extending the environment of the match expression with
these new bindings.  The value of the last <body> expression is returned as
the value of the match expression. 

The symbols QUOTE, VECTOR and ? are reserved in patterns to identify
literals, vectors and predicate tests.  Numbers, strings and
quoted literal <object>s must be EQUAL? to corresponding components of
<exp>s value, or the pattern fails.  <predicate> expressions should evaluate
to unary functions that are applied to the corresponding component of <exp>s
value when matching of the ? pattern is attempted.  If the predicate returns
false, the pattern fails.  Otherwise, the value applied to the predicate is
matched against the pattern following the predicate.

(match '(2 . 3) ((a . b) (* a b)))  ==>  6

(match '(1 2) ((a) a) ((a b) (+ a b)) (c c))  ==>  3

(match (list 33 "string" (vector 1 2)) 
  ((33 "string" (vector a b)) (cons a b)))  ==>  (1 . 2)

(let ((num 3))
  (match (cons 'x 4)
    (((? (lambda (v) (or (symbol? v) (and (number? v) (= v num)))) 
      . (? number? d)) (list c d))))  ==>  (x 4)

(match '(bar 3 4 5)
  (('foo x y) (cons x y))
  (('bar x y . z) (list x y z))
  (else (error "didn't match: " else)))  ==>  (3 4 5)

The most questionable feature of this proposal is the predicate
mechanism.  I like it, but some others here don't.  I'd like to have
others opinions, and would not mind if this feature were dropped.

A more significant issue is how to distinguish literal symbols from
pattern variables.  Scheme84 currently had an experimental match
facility that is similar to that above, but without a predicate
mechanism, with an optional else clause (rather than the ELSE variable
hack used above), and with a required list of pattern variables that
eliminated the need for literal quoting.  For example, in the current
version of Scheme84 the last example above would have required the pattern
variable list (x y z):

(match '(bar 3 4 . 5) (x y z)
  ((foo x y) (cons x y))
  ((bar x y . z) (list x y z))
  (else (error "No match")))  ==>  (3 4 5)

We found that remembering to update the list of pattern variables when
patterns were changed is a nuisance.  Also, the quote mechanism seems
more natural, simpler and more expressive than the pattern variable
list, so we no longer favor the pattern list approach.

I'd be quite happy if there were no other matching or destructuring
facility.  In the absense of a multiple value mechanism, I'd favor a
destructuring option for LET, e.g. (let (((x y) (cons 1 2))) ...);
however multiple values eliminates much of the need for this.  

If I were writing a system in which many functions had optional
arguments, I would want to write a macro like Jonathan's OPTIONALS,
but that could be done easily with match.  In other situations I might

(match-lambda pairs ...)  ==>  (lambda args (match args pairs ...)))	

or versions of lambda and let that destructured, but this sort of
thing probably doesn't belong in the standard.

-- Chris Haynes