util.match- Pattern matching
This module is a port of Andrew Wright’s pattern matching macro library.
It is widely used in Scheme world, and ported to various Scheme
implementations, including Chez Scheme, PLT Scheme, Scheme48, Chicken,
It is similar to, but more powerful than
This version retains compatibility of the original Wright’s macro, except (1) box is not supported since Gauche doesn’t have one, and (2) structure matching is integrated to Gauche’s object system.
We show a list of APIs first, then the table of complete syntax of patterns, followed by examples.
Each clause is either one of the followings:
(pat body …) (pat (=> identifier) body …)
First, the expr is matched against pat of each clauses. The detailed syntax of the pattern is explained below.
If a matching pat is found, the pattern variables in
pat are bound to the corresponding elements in expr, then
body … are evaluated. Then
match returns the value(s)
of the last expression of body ….
If the clause is the second form, identifier is also bound
to the failure continuation of the clause. It is a
procedure with no arguments, and when called, it jumps back to
the matcher as if the matching of pat is failed, and
match continues to try the rest of clauses.
So you can perform extra tests
within body … and if you’re not satisfied you can reject
the match by calling
(identifier). See the examples
below for more details.
If no pat matches,
match reports an error.
Creates a function that takes one argument and performs
match on it,
using clause …. It’s functionally equivalent to the following
(lambda (expr) (match expr clause …))
(map (match-lambda ((item price-per-lb (quantity 'lbs)) (cons item (* price-per-lb quantity))) ((item price-per-lb (quantity 'kg)) (cons item (* price-per-lb quantity 2.204)))) '((apple 1.23 (1.1 lbs)) (orange 0.68 (1.4 lbs)) (cantaloupe 0.53 (2.1 kg)))) ⇒ ((apple . 1.353) (orange . 0.952) (cantaloupe . 2.4530520000000005))
match-lambda, but performs
match on the list of
It’s functionally equivalent to the following expression:
(lambda expr (match expr clause …))
letrec to allow
patterns in the binding position rather than just variables.
Each expr is evaluated, and then matched to pat,
and the bound pattern variables are visible in
(match-let ( (((ca . cd) ...) '((a . 0) (b . 1) (c . 2))) ) (list ca cd)) ⇒ ((a b c) (0 1 2))
If you’re sick of parenthesis, try
This is a Gauche extension and isn’t found in the original Wright’s code. This one is equivalent to the following code:
(match-let ((pat expr)) body-expr …)
match-let1 is very close to the Common Lisp’s
(match-let1 ('let ((var val) ...) body ...) '(let ((a b) (c d)) foo bar baz) (list var val body)) ⇒ ((a c) (b d) (foo bar baz))
define, but allows a pattern instead of variables.
(match-define (x . xs) (list 1 2 3)) x ⇒ 1 xs ⇒ (2 3)
Here’s a summary of pattern syntax. The asterisk
after explanation means Gauche’s extension which does not present
in the original Wright’s code.
pat : patvar ;; anything, and binds pattern var | _ ;; anything | () ;; the empty list | #t ;; #t | #f ;; #f | string ;; a string | number ;; a number | character ;; a character | keyword ;; a keyword (*) | 'sexp ;; an s-expression | 'symbol ;; a symbol (special case of s-expr) | (pat1 ... patN) ;; list of n elements | (pat1 ... patN . patN+1) ;; list of n or more | (pat1 ... patN patN+1 ooo) ;; list of n or more, each element ;; of remainder must match patN+1 | #(pat1 ... patN) ;; vector of n elements | #(pat1 ... patN patN+1 ooo) ;; vector of n or more, each element ;; of remainder must match patN+1 | ($ class pat1 ... patN) ;; an object (patK matches in slot order) | (struct class pat1 ... patN) ;; ditto (*) | (@ class (slot1 pat1) ...) ;; an object (using slot names) (*) | (object class (slot1 pat1) ...) ;; ditto (*) | (= proc pat) ;; apply proc, match the result to pat | (and pat ...) ;; if all of pats match | (or pat ...) ;; if any of pats match | (not pat ...) ;; if all pats don't match at all | (? predicate pat ...) ;; if predicate true and all pats match | (set! patvar) ;; anything, and binds setter | (get! patvar) ;; anything, and binds getter | `qp ;; a quasi-pattern patvar : a symbol except _, quote, $, struct, @, object, =, and, or, not, ?, set!, get!, quasiquote, ..., ___, ..k, __k. ooo : ... ;; zero or more | ___ ;; zero or more | ..k ;; k or more, where k is an integer. ;; Example: ..1, ..2 ... | __k ;; k or more, where k is an integer. ;; Example: __1, __2 ...
__kwhere k is an integer.
_matches anything, without binding a pattern variable. It can be used to show "don’t care" placeholder.
equal?). You can use a quoted symbol to match the symbol itself.
As a special case, the last element of a vector or a list can be
followed by a symbol
.... In that case, the pattern just before
... can be applied repeatedly until it consumes all the
elements in the given expression. A symbol
___ can be used
in place of
...; it is useful when you want to produce a pattern
by syntax-rules macro.
For a list pattern, you can also use a symbol
…, which specifies the minimum number of repetition.
($ class pat1 …)matches an instance of a class
class. Each pattern
pat1… matches each value of slots, in order of
(struct class pat1 …) has the same meaning. Although
the original Wright’s code doesn’t have
struct, PLT Scheme has
it in its extended match feature, and it is more descriptive.
This is an adaptation of the original feature that can match structures.
It is useful to match a simple instance that you know the order of
slots; for example, a simple record created by
(see Record types) would be easy to match by positioned values.
If the instance’s class uses inheritances, it is a bit difficult to
match by positions. You can use
below to match using slot names.
(object class (slot1 pat1) …)matches an instance of a class
classwhose value of slot1 … matches pat1 …. This is Gauche’s extension.
@can be used in place of
objectis recommended because of descriptiveness.
(= proc pat)first applies proc to the corresponding expression, then match the result with pat.
(and pat …),
(or pat …), and
(not pat …)are boolean operations of patterns.
(? predicate pat …)first applies a predicate to the corresponding expression, and if it returns true, applies each
pat… to the expression.
(set! patvar)matches anything, and binds an one-argument procedure to a pattern variable patvar. If the procedure is called, it replaces the value of matched pattern for the given argument.
(get! patvar)matches anything, and binds a zero-argument procedure to a pattern variable patvar. If the procedure is called, it returns the matched value.
`qpis a quasipattern. qp is quoted, in the sense that it matches itself, except the pattern that is unquoted. (Don’t confuse quasipattern to quasiquote, though the functions are similar. Quasiquote turns off evaluation except unquoted subtree. Quasiquote turns off the special pattern syntax except unquoted subtree. See the examples below).
A simple structure decomposition:
(match '(0 (1 2) (3 4 5)) [(a (b c) (d e f)) (list a b c d e f)]) ⇒ (0 1 2 3 4 5)
Using predicate patterns:
(match 123 [(? string? x) (list 'string x)] [(? number? x) (list 'number x)]) ⇒ (number 123)
Extracting variables and expressions from
Uses repetition and predicate patterns:
(define let-analyzer (match-lambda [('let (? symbol?) ((var expr) ...) body ...) (format "named let, vars=~s exprs=~s" var expr)] [('let ((var expr) ...) body ...) (format "normal let, vars=~s exprs=~s" var expr)] [_ (format "malformed let")])) (let-analyzer '(let ((a b) (c d)) e f g)) ⇒ "normal let, vars=(a c) exprs=(b d)" (let-analyzer '(let foo ((x (f a b)) (y (f c d))) e f g)) ⇒ "named let, vars=(x y) exprs=((f a b) (f c d))" (let-analyzer '(let (a) b c d)) ⇒ "malformed let"
= function application. The pattern variable m
is matched to the result of application of the regular expression.
(match "gauche-ref.texi" ((? string? (= #/(.*)\.([^.]+)$/ m)) (format "base=~a suffix=~a" (m 1) (m 2)))) ⇒ "base=gauche-ref suffix=texi"
An example of quasipattern. In the first expression, the
value is quoted, so the symbols
is are not pattern variables but literal
symbols. The second expression shows that; input symbol
does not match the literal symbol
is in the pattern.
If we don’t use quasiquote, all symbols in the pattern are pattern
variables, so any four-element list matches as the third expression shows.
(match '(the answer is 42) [`(the answer is ,value) value] [else #f]) ⇒ 42 (match '(the answer was 42) [`(the answer is ,value) value] [else #f]) ⇒ #f (match '(a b c d) [(the answer is value) value] [else #f]) ⇒ d