A pattern matcher.This pattern matcher is a portable version of Chez Scheme's match by Dan Friedman, Erik Hilsdale, and Kent Dybvig.
Amatch
expression looks a lot like a
case
expression, except that the keys
are replaced with a pattern to match against the
input.
A match expression has the general form(match <expr> <clause> ...)
,
where <expr>
in the input expression
to match and each clause has one of the forms(<pattern> <body1> <body2> ...)
, and(<pattern> (guard <guard-expr>) <body1> <body2> ...)
.
As with case
, the input expression is evaluated to produce
the input value and the first clause the input value matches, if any,
is selected.
The body <body1> <body2> ...
of the selected clause is
evaluated in sequence, and the values of the last expression are
returned.
An input value matches a clause if it fits the clause's pattern and
the guard expression <guard-expr>
, if any, evaluates to a
true value.
Patterns may contain symbolic constants, which must match exactly,
and pattern variables, which match any input. Pattern variables
are prefixed by commas; symbolic constants are not.
(match '(a 17 37)
((a ,x) 1)
((b ,x ,y) 2)
((a ,x ,y) 3))
=> 3
b
does not match a
.
In the output expression, the values of the pattern variables are
bound to the corresponding pieces of input.
(match '(a 17 37)
((a ,x) (- x))
((b ,x ,y) (+ x y))
((a ,x ,y) (* x y)))
=> 629
...
), a pattern variable
represents a sequence of input values.
(match '(a 17 37) ((a ,x* ...) x*))
=> (17 37)
(match '(begin (1 5) (2 6) (3 7) (4 8))
((begin (,x* ,y*) ...) (append x* y*)))
=> (1 2 3 4 5 6 7 8)
(match '((a b c d) (e f g) (h i) (j))
(((,x* ,y** ...) ...) (list x* y**)))
=> ((a e h j) ((b c d) (f g) (i) ()))
match
. Here, a procedure returning the length of a list
is defined.
(letrec
((len
(lambda (lst)
(match lst
(() 0)
((,x ,x* ...) (+ 1 (len x*)))))))
(len '(a b c d)))
=> 4
match
. If a pattern variable is written as ,(<var>)
,
match
recurs on the matching subpart of the input before
evaluating the output expressions of the clause.
(let ((len
(lambda (lst)
(match lst
(() 0)
((,x . ,(x*)) (+ 1 x*))))))
(len '(a b c d)))
=> 4
match
will need to return multiple values.
The catamorphism syntax can be used to receive multiple values.
When making implicit recursive calls using the catamorphism syntax,
zero or more variables between the brackets can be included, each
representing one of the expected return values.
(let ((split
(lambda (lis)
(match lis
(() (values '() '()))
((,x) (values `(,x) '()))
((,x ,y . ,(odds evens)) (values `(,x . ,odds)
`(,y . ,evens)))))))
(split '(a b c d e f)))
=> ((values) (a c e) (b d f))
,(<var> ...)
recurs to the top of the
current match
, ,(<cata> -> <var> ...)
recurs to
<cata>
. <Cata>
must evaluate to a procedure that
accepts one argument, the input expression, and returns as many
values as there are identifiers following the ->
.
Here is an example that illustrates the use of guards and how to achieve the
effect of a catch-all clause.
(let ((simple-eval
(lambda (x)
(match x
(,i (guard (integer? i)) i)
((+ ,(x*) ...) (apply + x*))
((* ,(x*) ...) (apply * x*))
((- ,(x) ,(y)) (- x y))
((/ ,(x) ,(y)) (/ x y))
(,x (error "simple-eval: invalid expression" x))))))
(simple-eval '(+ (- 0 1) (+ 2 3))))
=> 4
<expr>
is matched against each
<clause>
in turn,
according to the rules described in the previous section,
until the the first clause matches. When a match is found, the
corresponding body is evaluated, and the values of the last expression are
returned as the result of the entire match. It is an error if no pattern
matches.
Equivalent to the (match <expr> <clause> ...)
with the
following exceptions: If <unbox>
is not #f
,
each input expression is converted with <unbox>
before matched against a list or vector pattern. If <loop>
is not #f
, catamorphism subpatterns recur to <loop>
if no explicit operator is named.
Auxiliary syntax.