8 Pattern Matching
Pattern Matching in Guide: Racket 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.
(match val-expr clause ...) | ||||||||||
|
The clauses are tried in order to find a match. If no clause matches, then the exn:misc:match? exception is raised.
An optional (=> id) between a pat and the exprs is bound to a failure procedure of zero arguments. 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 exprs must not mutate the object being matched before calling the failure procedure, otherwise the behavior of matching is unpredictable.
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 |
|
| | |
| _ |
| 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-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-table (pat pat) ...) |
| match hash table |
|
| | |
| (hash-table (pat pat) ...+ ooo) |
| match hash table |
|
| | |
| (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 pat) |
| match (expr value) to pat |
|
| | |
| (? 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 |
|
| | |
| ,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 |
In more detail, patterns match as follows:
id, excluding the reserved names _, ..., .._, ..k, and ..k for non-negative integers k – 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.
Examples:
> (match '(1 2 3) [(list a b a) (list a b)] [(list a b c) (list c b a)]) '(3 2 1)
> (match '(1 '(x y z) 1) [(list a b a) (list a b)] [(list a b c) (list c b a)]) '(1 '(x y z))
_ – matches anything, without binding any identifiers.
Example:
> (match '(1 2 3) [(list _ _ a) a]) 3
#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 element 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 synonyms for zero or more matches. The ..k and __k forms are also synonyms, 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) – 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:
> (match '(1 2 3 . 4) [(list-rest a b c d) d]) 4
> (match '(1 2 3 . 4) [(list-rest a ... d) (list a d)]) '((1 2 3) 4)
(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
(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:
> (match '(1 2 3 4 5 6) [(list-no-order 6 2 y ...) y]) '(1 3 4 5)
(vector lvp ...) – like a list pattern, but matching a vector.
Example:
> (match #(1 (2) (2) (2) 5) [(vector 1 (list a) ..3 5) a]) '(2 2 2)
(hash-table (pat pat) ...) – similar to list-no-order, but matching against hash table’s key–value pairs.
Example:
> (match #hash(("a" . 1) ("b" . 2)) [(hash-table ("b" b) ("a" a)) (list b a)]) '(2 1)
(hash-table (pat pat) ...+ ooo) – Generalizes hash-table to support a final repeating pattern.
Example:
> (match #hash(("a" . 1) ("b" . 2)) [(hash-table (key val) ...) key]) '("a" "b")
(cons pat1 pat2) – matches a pair value.
Example:
> (match (cons 1 2) [(cons a b) (+ a b)]) 3
(mcons pat1 pat2) – matches a mutable pair value.
Example:
> (match (mcons 1 2) [(cons a b) 'immutable] [(mcons a b) 'mutable]) 'mutable
(box pat) – matches a boxed value.
Example:
> (match #&1 [(box a) a]) 1
(struct-id pat ...) or (struct struct-id (pat ...)) – matches an instance of a structure type names 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:
(define-struct tree (val left right)) > (match (make-tree 0 (make-tree 1 #f #f) #f) [(tree a (tree b _ _) _) (list a b)]) '(0 1)
(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; see Regular Expressions for more information about regexps.
Examples:
> (match "apple" [(regexp #rx"p+") 'yes] [_ 'no]) 'yes
> (match "banana" [(regexp #rx"p+") '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:
> (match "apple" [(regexp #rx"p+(.)" (list _ "l")) 'yes] [_ 'no]) 'yes
> (match "append" [(regexp #rx"p+(.)" (list _ "l")) 'yes] [_ 'no]) 'no
(pregexp rx-expr) or (regexp rx-expr pat) – like the regexp patterns, but if rx-expr produces a string, it is converted to a pattern using pregexp instead of regexp.
(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.
Example:
> (match '(1 (2 3) 4) [(list _ (and a (list _ ...)) _) a]) '(2 3)
(or pat ...) – matches if any of the pats match. Beware: the result expression can be duplicated once for each pat! Identifiers in pat are bound only in the corresponding copy of the result expression; in a module context, if the result expression refers to a binding, then that all pats must include the binding.
Example:
> (match '(1 2) [(or (list a 1) (list a 2)) a]) 1
(not pat ...) – matches when none of the pats match, and binds no identifiers.
Examples:
> (match '(1 2 3) [(list (not 4) ...) 'yes] [_ 'no]) 'yes
> (match '(1 4 3) [(list (not 4) ...) 'yes] [_ 'no]) 'no
(app expr pat) – applies expr to the value to be matched; the result of the application is matched againt pat.
Example:
> (match '(1 2) [(app length 2) 'yes]) 'yes
(? 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).
Example:
> (match '(1 3 5) [(list (? odd?) ...) 'yes]) 'yes
(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:
> (match '(1 2 3) [`(1 ,a ,(? odd? b)) (list a b)]) '(2 3)
derived-pattern – matches a pattern defined by a macro extension via define-match-expander.
8.1 Combined Matching Forms
(match-lambda clause ...) |
(match-lambda* clause ...) |
(match-let ([pat expr] ...) body ...+) |
Example: | |||
| |||
'(2 1 (1 2 3 4)) |
(match-let* ([pat expr] ...) body ...+) |
Example: | |||
| |||
'(1 2 3 4) |
(match-letrec ([pat expr] ...) body ...+) |
(match-define pat expr) |
Examples: |
> (match-define (list a b) '(1 2)) |
> b |
2 |
(exn:misc:match? v) → boolean? |
v : any/c |
8.2 Extending match
(define-match-expander id proc-expr) |
(define-match-expander id proc-expr proc-expr) |
The first proc-expr subexpression 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 the replaced with the result of the transformer.
A transformer produced by a second proc-expr subexpression 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-equality-test) → (any/c any/c . -> . any) |
(match-equality-test comp-proc) → void? |
comp-proc : (any/c any/c . -> . any) |
8.3 Library Extensions
(struct* struct-id ([field pat] ...)) |
Any field of struct-id may be omitted and they may occur in any order.
Examples: | ||||
| ||||
| ||||
'(0 1) |