racket/collects/scribblings/guide/match.scrbl
Robby Findler 74f8b0e2f1 add a little more about quasiquote to the guide
Please merge to the 5.1 release branch
2011-02-04 13:08:12 -06:00

156 lines
4.1 KiB
Racket

#lang scribble/doc
@(require scribble/manual
scribble/eval
"guide-utils.ss"
(for-label racket/match))
@(begin
(define match-eval (make-base-eval))
(interaction-eval #:eval match-eval (require racket/match)))
@title[#:tag "match"]{Pattern Matching}
The @racket[match] form supports pattern matching on arbitrary Racket
values, as opposed to functions like @racket[regexp-match] that
compare regular expressions to byte and character sequences (see
@secref["regexp"]).
@specform[
(match target-expr
[pattern expr ...+] ...)
]
The @racket[match] form takes the result of @racket[target-expr] and
tries to match each @racket[_pattern] in order. As soon as it finds a
match, it evaluates the corresponding @racket[_expr] sequence to
obtain the result for the @racket[match] form. If @racket[_pattern]
includes @deftech{pattern variables}, they are treated like wildcards,
and each variable is bound in the @racket[_expr] to the input
fragments that it matched.
Most Racket literal expressions can be used as patterns:
@interaction[
#:eval match-eval
(match 2
[1 'one]
[2 'two]
[3 'three])
(match #f
[#t 'yes]
[#f 'no])
(match "apple"
['apple 'symbol]
["apple" 'string]
[#f 'boolean])
]
Constructors like @racket[cons], @racket[list], and @racket[vector]
can be used to create patterns that match pairs, lists, and vectors:
@interaction[
#:eval match-eval
(match '(1 2)
[(list 0 1) 'one]
[(list 1 2) 'two])
(match '(1 . 2)
[(list 1 2) 'list]
[(cons 1 2) 'pair])
(match #(1 2)
[(list 1 2) 'list]
[(vector 1 2) 'vector])
]
A constructor bound with @scheme[struct] also can be used as a pattern
constructor:
@interaction[
#:eval match-eval
(struct shoe (size color))
(struct hat (size style))
(match (hat 23 'bowler)
[(shoe 10 'white) "bottom"]
[(hat 23 'bowler) "top"])
]
Unquoted, non-constructor identifiers in a pattern are @tech{pattern
variables} that are bound in the result expressions:
@interaction[
#:eval match-eval
(match '(1)
[(list x) (+ x 1)]
[(list x y) (+ x y)])
(match '(1 2)
[(list x) (+ x 1)]
[(list x y) (+ x y)])
(match (hat 23 'bowler)
[(shoe sz col) sz]
[(hat sz stl) sz])
]
An ellipsis, written @litchar{...}, act like a Kleene star within a
list or vector pattern: the preceding sub-pattern can be used to match
any number of times for any number of consecutive elements of the list
of vector. If a sub-pattern followed by an ellipsis includes a pattern
variable, the variable matches multiple times, and it is bound in the
result expression to a list of matches:
@interaction[
#:eval match-eval
(match '(1 1 1)
[(list 1 ...) 'ones]
[else 'other])
(match '(1 1 2)
[(list 1 ...) 'ones]
[else 'other])
(match '(1 2 3 4)
[(list 1 x ... 4) x])
(match (list (hat 23 'bowler) (hat 22 'pork-pie))
[(list (hat sz styl) ...) (apply + sz)])
]
Ellipses can be nested to match nested repetitions, and in that case,
pattern variables can be bound to lists of lists of matches:
@interaction[
#:eval match-eval
(match '((! 1) (! 2 2) (! 3 3 3))
[(list (list '! x ...) ...) x])
]
The @racket[quasiquote] form (see @secref["qq"] for more about it) can also be used to build patterns.
While unquoted portions of a normal quasiquoted form mean regular racket evaluation, here unquoted
portions mean go back to regular pattern matching.
So, in the example below, the with expression is the pattern and it gets rewritten into the
application expression, using quasiquote as a pattern in the first instance and quasiquote
to build an expression in the second.
@interaction[
#:eval match-eval
(match `{with {x 1} {+ x 1}}
[`{with {,id ,rhs} ,body}
`{{lambda {,id} ,body} ,rhs}])
]
For information on many more pattern forms, see @racketmodname[racket/match].
Forms like @racket[match-let] and @racket[match-lambda] support
patterns in positions that otherwise must be identifiers. For example,
@racket[match-let] generalizes @racket[let] to a @as-index{destructing
bind}:
@interaction[
#:eval match-eval
(match-let ([(list x y z) '(1 2 3)])
(list z y x))
]
For information on these additional forms, see @racketmodname[racket/match].
@refdetails["match"]{pattern matching}
@close-eval[match-eval]