9 Pattern Matching
Pattern Matching in The Racket Guide introduces pattern matching.
The match form and related forms support general pattern matching on Racket values. See also Regular Expressions for information on regular-expression matching on strings, bytes, and streams.
(require racket/match) | package: base |
syntax
(match val-expr clause ...)
clause = [pat option=> option ... body ...+] option=> =
| (=> id) option = #:when cond-expr | #:do [do-body ...]
To find a match, the clauses are tried in order. If no clause matches, then the exn:misc:match? exception is raised.
An optional #:when cond-expr specifies that the pattern should only match if cond-expr produces a true value. cond-expr is in the scope of all of the variables bound in pat. cond-expr must not mutate the object being matched before calling the failure procedure, otherwise the behavior of matching is unpredictable. See also failure-cont, which is a lower-level mechanism achieving the same ends.
> (define (m x) (match x [(list a b c) #:when (= 6 (+ a b c)) 'sum-is-six] [(list a b c) 'sum-is-not-six])) > (m '(1 2 3)) 'sum-is-six
> (m '(2 3 4)) 'sum-is-not-six
An optional #:do [do-body ...] executes do-body forms. In particular, the forms may introduce definitions that are visible in the remaining options and the main clause body. Both #:when and #:do options may appear multiple times
> (define (m x) (match x [(list a b c) #:do [(define sum (+ a b c))] #:when (> sum 6) (format "the sum, which is ~a, is greater than 6" sum)] [(list a b c) 'sum-is-not-greater-than-six])) > (m '(1 2 3)) 'sum-is-not-greater-than-six
> (m '(2 3 4)) "the sum, which is 9, is greater than 6"
An optional (=> id), which must appear immediately after pat, is bound to a failure procedure of zero arguments. id is visible in all clause options and the clause body. If this procedure is invoked, it escapes back to the pattern matching expression, and resumes the matching process as if the pattern had failed to match. The bodys must not mutate the object being matched before calling the failure procedure, otherwise the behavior of matching is unpredictable.
> (define (m x) (match x [(list a b c) (=> exit) (f x exit)] [(list a b c) 'sum-is-not-six]))
> (define (f x exit) (if (= 6 (apply + x)) 'sum-is-six (exit))) > (m '(1 2 3)) 'sum-is-six
> (m '(2 3 4)) 'sum-is-not-six
The grammar of pat is as follows, where non-italicized identifiers are recognized symbolically (i.e., not by binding).
pat |
| ::= |
| id |
| match anything, bind identifier |
|
| | |
| (var id) |
| match anything, bind identifier |
|
| | |
| _ |
| match anything |
|
| | |
| literal |
| match literal |
|
| | |
| (quote datum) |
| match equal? value |
|
| | |
| (list lvp ...) |
| match sequence of lvps |
|
| | |
| (list-rest lvp ... pat) |
| match lvps consed onto a pat |
|
| | |
| (list* lvp ... pat) |
| match lvps consed onto a pat |
|
| | |
| (list-no-order pat ...) |
| match pats in any order |
|
| | |
| (list-no-order pat ... lvp) |
| match pats in any order |
|
| | |
| (vector lvp ...) |
| match vector of pats |
|
| | |
| (hash expr pat ... ... ht-opt) |
| match hash table |
|
| | |
| (hash* [expr pat kv-opt] ... ht-opt) |
| match hash table |
|
| | |
| (hash-table (pat pat) ...) |
| match hash table - deprecated |
|
| | |
| (hash-table (pat pat) ...+ ooo) |
| match hash table - deprecated |
|
| | |
| (cons pat pat) |
| match pair of pats |
|
| | |
| (mcons pat pat) |
| match mutable pair of pats |
|
| | |
| (box pat) |
| match boxed pat |
|
| | |
| (struct-id pat ...) |
| match struct-id instance |
|
| | |
| (struct struct-id (pat ...)) |
| match struct-id instance |
|
| | |
| (regexp rx-expr) |
| match string |
|
| | |
| (regexp rx-expr pat) |
| match string, result with pat |
|
| | |
| (pregexp px-expr) |
| match string |
|
| | |
| (pregexp px-expr pat) |
| match string, result with pat |
|
| | |
| (and pat ...) |
| match when all pats match |
|
| | |
| (or pat ...) |
| match when any pat match |
|
| | |
| (not pat ...) |
| match when no pat matches |
|
| | |
| (app expr pats ...) |
| match (expr value) output values to pats |
|
| | |
| (? expr pat ...) |
| match if (expr value) and pats |
|
| | |
| (quasiquote qp) |
| match a quasipattern |
|
| | |
| derived-pattern |
| match using extension |
literal |
| ::= |
| #t |
| match true |
|
| | |
| #f |
| match false |
|
| | |
| string |
| match equal? string |
|
| | |
| bytes |
| match equal? byte string |
|
| | |
| number |
| match equal? number |
|
| | |
| char |
| match equal? character |
|
| | |
| keyword |
| match equal? keyword |
|
| | |
| regexp |
| match equal? regexp literal |
|
| | |
| pregexp |
| match equal? pregexp literal |
lvp |
| ::= |
| pat ooo |
| greedily match pat instances |
|
| | |
| pat |
| match pat |
qp |
| ::= |
| literal |
| match literal |
|
| | |
| id |
| match symbol |
|
| | |
| (qp ...) |
| match sequences of qps |
|
| | |
| (qp ... . qp) |
| match qps ending qp |
|
| | |
| (qp ooo . qp) |
| match qps beginning with repeated qp |
|
| | |
| #(qp ...) |
| match vector of qps |
|
| | |
| #&qp |
| match boxed qp |
|
| | |
| #s(prefab-key qp ...) |
| match prefab struct with qp fields |
|
| | |
| ,pat |
| match pat |
|
| | |
| ,@(list lvp ...) |
| match lvps, spliced |
|
| | |
| ,@(list-rest lvp ... pat) |
| match lvps plus pat, spliced |
|
| | |
| ,@'qp |
| match list-matching qp, spliced |
ooo |
| ::= |
| ... |
| zero or more; ... is literal |
|
| | |
| ___ |
| zero or more |
|
| | |
| ..k |
| k or more |
|
| | |
| __k |
| k or more |
kv-opt |
| ::= |
|
| key must exist | |
|
| | |
| #:default def-expr |
| key may not exist; match def-expr with the value pattern |
ht-opt |
| ::= |
|
| default mode | |
|
| | |
| #:closed |
| closed to extension mode |
|
| | |
| #:open |
| open to extension mode |
|
| | |
| #:rest pat |
| residue mode |
In more detail, patterns match as follows:
- id (excluding the reserved names _, ..., ___, ..k, and __k for non-negative integers k)or (var id) —
matches anything, and binds id to the matching values. If an id is used multiple times within a pattern, the corresponding matches must be the same according to (match-equality-test), except that instances of an id in different or and not sub-patterns are independent. The binding for id is not available in other parts of the same pattern. Examples: _ —
matches anything, without binding any identifiers. Example:#t, #f, string, bytes, number, char, or (quote datum) —
matches an equal? constant. Example:> (match "yes" ["no" #f] ["yes" #t]) #t
(list lvp ...) —
matches a list of elements. In the case of (list pat ...), the pattern matches a list with as many elements as pats, and each element must match the corresponding pat. In the more general case, each lvp corresponds to a “spliced” list of greedy matches. For spliced lists, ... and ___ are aliases for zero or more matches. The ..k and __k forms are also aliases, specifying k or more matches. Pattern variables that precede these splicing operators are bound to lists of matching forms.
Examples:> (match '(1 2 3) [(list a b c) (list c b a)]) '(3 2 1)
> (match '(1 2 3) [(list 1 a ...) a]) '(2 3)
> (match '(1 2 3) [(list 1 a ..3) a] [_ 'else]) 'else
> (match '(1 2 3 4) [(list 1 a ..3) a] [_ 'else]) '(2 3 4)
> (match '(1 2 3 4 5) [(list 1 a ..3 5) a] [_ 'else]) '(2 3 4)
> (match '(1 (2) (2) (2) 5) [(list 1 (list a) ..3 5) a] [_ 'else]) '(2 2 2)
(list-rest lvp ... pat) or (list* lvp ... pat) —
similar to a list pattern, but the final pat matches the “rest” of the list after the last lvp. In fact, the matched value can be a non-list chain of pairs (i.e., an “improper list”) if pat matches non-list values. Examples:(list-no-order pat ...) —
similar to a list pattern, but the elements to match each pat can appear in the list in any order. Example:> (match '(1 2 3) [(list-no-order 3 2 x) x]) 1
Unlike other patterns, list-no-order doesn’t allow duplicate identifiers between subpatterns. For example the patterns (list-no-order x 1 x) and (list-no-order x 1 x ...) both produce syntax errors.
(list-no-order pat ... lvp) —
generalizes list-no-order to allow a pattern that matches multiple list elements that are interspersed in any order with matches for the other patterns. Example:(vector lvp ...) —
like a list pattern, but matching a vector. Example:(hash expr pat ... ... ht-opt) —
matches against a hash table where expr matches a key and pat matches a corresponding value. Examples:> (match (hash "aa" 1 "b" 2) [(hash "b" b (string-append "a" "a") a) (list b a)]) '(2 1)
> (match (hash "aa" 1 "b" 2) [(hash "b" _ "c" _) 'matched] [_ 'not-matched]) 'not-matched
The key matchings use the key comparator of the matching hash table.
Examples:> (let ([k (string-append "a" "b")]) (match (hasheq "ab" 1) [(hash k v) 'matched] [_ 'not-matched])) 'not-matched
> (let ([k (string-append "a" "b")]) (match (hasheq k 1) [(hash k v) 'matched] [_ 'not-matched])) 'matched
The behavior of residue key-value entries in the hash table value depends on ht-opt.
When ht-opt is not provided or when it is #:closed, all of the keys in the hash table value must be matched. I.e., the matching is closed to extension.
Example:When ht-opt is #:open, there can be keys in the hash table value that are not specified in the pattern. I.e., the matching is open to extension.
Example:When ht-opt is #:rest pat, pat is further matched against the residue hash table. If the matching hash table is immutable, this residue matching is efficient. Otherwise, the matching hash table will be copied, which could be expensive.
Example:Many key exprs could evaluate to the same value.
Example:(hash* [expr pat kv-opt] ... ht-opt) —
similar to hash, but with the following differences: The key-value pattern must be grouped syntactically.
If ht-opt is not specified, it behaves like #:open (as opposed to #:closed).
If kv-opt is specified with #:default def-expr, and the key does not exist in the hash table value, then the default value from def-expr will be matched against the value pattern, instead of immediately failing to match.
Examples:(hash-table (pat pat) ...) —
This pattern is deprecated because it can be incorrect. However, many programs rely on the incorrect behavior, so we still provide this pattern for backward compatibility reasons. Similar to list-no-order, but matching against hash table’s key–value pairs.
Example:(hash-table (pat pat) ...+ ooo) —
This pattern is deprecated because it can be incorrect. However, many programs rely on the incorrect behavior, so we still provide this pattern for backward compatibility reasons. Generalizes hash-table to support a final repeating pattern.
Example:(cons pat1 pat2) —
matches a pair value. Example:(mcons pat1 pat2) —
matches a mutable pair value. Example:(box pat) —
matches a boxed value. Example:(struct-id pat ...) or (struct struct-id (pat ...)) —
matches an instance of a structure type named struct-id, where each field in the instance matches the corresponding pat. See also struct*. Usually, struct-id is defined with struct. More generally, struct-id must be bound to expansion-time information for a structure type (see Structure Type Transformer Binding), where the information includes at least a predicate binding and field accessor bindings corresponding to the number of field pats. In particular, a module import or a unit import with a signature containing a struct declaration can provide the structure type information.
Examples:(struct struct-id _) —
matches any instance of struct-id, without regard to contents of the fields of the instance. (regexp rx-expr) —
matches a string that matches the regexp pattern produced by rx-expr, where rx-expr can be either a regexp, a pregexp, a byte-regexp, a byte-pregexp, a string, or a byte string. A string and byte string value is converted to a pattern using regexp and byte-regexp respectively. See Regular Expressions for more information about regexps. Examples:> (match "apple" [(regexp #rx"p+") 'yes] [_ 'no]) 'yes
> (match "banana" [(regexp #px"(na){2}") 'yes] [_ 'no]) 'yes
> (match "banana" [(regexp "(na){2}") 'yes] [_ 'no]) 'no
> (match #"apple" [(regexp #rx#"p+") 'yes] [_ 'no]) 'yes
> (match #"banana" [(regexp #px#"(na){2}") 'yes] [_ 'no]) 'yes
> (match #"banana" [(regexp #"(na){2}") 'yes] [_ 'no]) 'no
(regexp rx-expr pat) —
extends the regexp form to further constrain the match where the result of regexp-match is matched against pat. Examples:(pregexp rx-expr) or (pregexp rx-expr pat) —
like the regexp patterns, but rx-expr must be either a pregexp, a byte-pregexp, a string, or a byte string. A string and byte string value is converted to a pattern using pregexp and byte-pregexp respectively. (and pat ...) —
matches if all of the pats match. This pattern is often used as (and id pat) to bind id to the entire value that matches pat. The pats are matched in the order that they appear. Example:(or pat ...) —
matches if any of the pats match. Each pat must bind the same set of identifiers. Example:(not pat ...) —
matches when none of the pats match, and binds no identifiers. Examples:(app expr pats ...) —
applies expr to the value to be matched; each result of the application is matched against one of the pats, respectively. Examples:(? expr pat ...) —
applies expr to the value to be matched, and checks whether the result is a true value; the additional pats must also match; i.e., ? combines a predicate application and an and pattern. However, ?, unlike and, guarantees that expr is matched before any of the pats. The expr procedure may be called more than once on identical input (although this happens only rarely), and the order in which calls to expr are made should not be relied upon.
Example:(quasiquote qp) —
introduces a quasipattern, in which identifiers match symbols. Like the quasiquote expression form, unquote and unquote-splicing escape back to normal patterns. Example:derived-pattern —
matches a pattern defined by a macro extension via define-match-expander.
Note that the matching process may destructure the input multiple times, and may evaluate expressions embedded in patterns such as (app expr pat) in arbitrary order, or multiple times. Therefore, such expressions must be safe to call multiple times, or in an order other than they appear in the original program.
Changed in version 8.9.0.5 of package base: Added a support for #:do.
Changed in version 8.11.1.10: Added the hash and
hash* patterns.
9.1 Additional Matching Forms
syntax
(match* (val-expr ...+) clause* ...)
clause* = [(pat ...+) option=> option ... body ...+]
> (match* (1 2 3) [(_ (? number?) x) (add1 x)]) 4
> (match* (15 17) [((? number? a) (? number? b)) #:when (= (+ a 2) b) 'diff-by-two]) 'diff-by-two
syntax
(match/values expr clause* clause* ...)
> (match/values (values 1 2 3) [(a (? number? b) (? odd? c)) (+ a b c)]) 6
syntax
(define/match (head args) match*-clause ...)
head = id | (head args) args = arg ... | arg ... . rest-id arg = arg-id | [arg-id default-expr] | keyword arg-id | keyword [arg-id default-expr] match*-clause = [(pat ...+) option=> option ... body ...+]
(define/match (fact n) [(0) 1] [(n) (* n (fact (sub1 n)))])
> (fact 5) 120
The function header may also contain optional or keyword arguments, may have curried arguments, and may also contain a rest argument.
(define/match ((f x) #:y [y '(1 2 3)]) [((regexp #rx"p+") `(,a 2 3)) a] [(_ _) #f])
> ((f "ape") #:y '(5 2 3)) 5
> ((f "dog")) #f
(define/match (g x y . rst) [(0 0 '()) #t] [(5 5 '(5 5)) #t] [(_ _ _) #f])
> (g 0 0) #t
> (g 5 5 5 5) #t
> (g 1 2) #f
syntax
(match-lambda clause ...)
syntax
(match-λ clause ...)
Changed in version 8.13.0.5 of package base: Added match-λ.
syntax
(match-lambda* clause ...)
syntax
(match-λ* clause ...)
Changed in version 8.13.0.5 of package base: Added match-λ*.
syntax
(match-lambda** clause* ...)
syntax
(match-λ** clause ...)
Changed in version 8.13.0.5 of package base: Added match-λ**.
syntax
(match-let ([pat expr] ...) body ...+)
syntax
(match-let* ([pat expr] ...) body ...+)
> (match-let* ([(list a b) '(#(1 2 3 4) 2)] [(vector x ...) a]) x) '(1 2 3 4)
syntax
(match-let-values ([(pat ...) expr] ...) body ...+)
syntax
(match-let*-values ([(pat ...) expr] ...) body ...+)
syntax
(match-letrec ([pat expr] ...) body ...+)
syntax
(match-letrec-values ([(pat ...) expr] ...) body ...+)
Added in version 6.1.1.8 of package base.
syntax
(match-define pat expr)
> (match-define (list a b) '(1 2)) > b 2
syntax
(match-define-values (pat pats ...) expr)
> (match-define-values (a b) (values 1 2)) > b 2
procedure
(exn:misc:match? v) → boolean?
v : any/c
syntax
9.2 Extending match
syntax
(define-match-expander id proc-expr)
(define-match-expander id proc-expr proc-expr)
The first proc-expr sub-expression must evaluate to a transformer that produces a pat for match. Whenever id appears as the beginning of a pattern, this transformer is given, at expansion time, a syntax object corresponding to the entire pattern (including id). The pattern is replaced with the result of the transformer.
A transformer produced by a second proc-expr sub-expression is used when id is used in an expression context. Using the second proc-expr, id can be given meaning both inside and outside patterns.
Match expanders are not invoked unless id appears in the first position in a sequence. Instead, identifiers bound by define-match-expander are used as binding identifiers (like any other identifier) when they appear anywhere except the first position in a sequence.
(define (syntax-list? x) (and (syntax? x) (list? (syntax->list x)))) (define-match-expander syntax-list (lambda (stx) (syntax-case stx () [(_ elts ...) #'(? syntax-list? (app syntax->list (list elts ...)))]))) (define (make-keyword-predicate keyword) (lambda (stx) (and (identifier? stx) (free-identifier=? stx keyword)))) (define or-keyword? (make-keyword-predicate #'or)) (define and-keyword? (make-keyword-predicate #'and))
> (match #'(or 3 4) [(syntax-list (? or-keyword?) b c) (list "OOORRR!" b c)] [(syntax-list (? and-keyword?) b c) (list "AAANND!" b c)]) '("OOORRR!" #<syntax:eval:88:0 3> #<syntax:eval:88:0 4>)
> (match #'(and 5 6) [(syntax-list (? or-keyword?) b c) (list "OOORRR!" b c)] [(syntax-list (? and-keyword?) b c) (list "AAANND!" b c)]) '("AAANND!" #<syntax:eval:89:0 5> #<syntax:eval:89:0 6>)
(define-match-expander nil (λ (stx) #''()) (λ (stx) #''())) (define (len l) (match l [nil 0] [(cons hd tl) (+ 1 (len tl))]))
Because there are no parenthesis around nil, match treats the first case as an identifier (which matches everything) instead of a use of the match expander and len always returns 0.
> (len nil) 0
> (len (cons 1 nil)) 0
> (len (cons 1 (cons 2 nil))) 0
(define-match-expander my-vector (λ (stx) (syntax-case stx () [(_ pat ...) #'(vector pat ...)] [(_ pat ... . rest-pat) #'(app vector->list (list-rest pat ... rest-pat))])))
> (match #(1 2 3 4 5) [(my-vector a b . rest) (list->vector (append rest (list a b)))]) '#(3 4 5 1 2)
Changed in version 7.7.0.2 of package base: Match expanders now allowed any syntax pair whose first element is an identifier? bound to the expander. The example above did not work with previous versions.
The property value must be an exact non-negative integer or a procedure of one or two arguments. In the former case, the integer designates a field within the structure that should contain a procedure; the integer must be between 0 (inclusive) and the number of non-automatic fields in the structure type (exclusive, not counting supertype fields), and the designated field must also be specified as immutable.
If the property value is a procedure of one argument, then the procedure serves as the transformer for match expansion. If the property value is a procedure of two arguments, then the first argument is the structure whose type has prop:match-expander property, and the second argument is a syntax object as for a match expander..
If the property value is a assignment transformer, then the wrapped procedure is extracted with set!-transformer-procedure before it is called.
This binding is provided for-syntax.
This binding is provided for-syntax.
procedure
(match-expander? v) → boolean?
v : any/c
procedure
v : any/c
procedure
(syntax-local-match-introduce stx) → syntax?
stx : syntax?
Changed in version 6.90.0.29 of package base: Made equivalent to syntax-local-introduce.
parameter
(match-equality-test) → (any/c any/c . -> . any)
(match-equality-test comp-proc) → void? comp-proc : (any/c any/c . -> . any)
syntax
(match/derived val-expr original-datum clause ...)
syntax
(match*/derived (val-expr ...) original-datum clause* ...)
9.3 Library Extensions
> (match (list 1 2 3) [(== (list 1 2 3)) 'yes] [_ 'no]) 'yes
> (match (list 1 2 3) [(== (list 1 2 3) eq?) 'yes] [_ 'no]) 'no
> (match (list 1 2 3) [(list 1 2 (== 3 =)) 'yes] [_ 'no]) 'yes
syntax
(struct* struct-id ([field pat] ...))
Any field of struct-id may be omitted, and such fields can occur in any order.