2022-08-02 12:34:59 +02:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta name = "generator" content =
"HTML Tidy for HTML5 for Linux version 5.2.0">
< title > Pattern Matching< / title >
< meta charset = "utf-8" >
< meta name = "description" content = "A collection of examples of using Common Lisp" >
< meta name = "viewport" content =
"width=device-width, initial-scale=1">
2022-08-04 11:37:48 +02:00
< link rel = "icon" href =
"assets/cl-logo-blue.png"/>
2022-08-02 12:34:59 +02:00
< link rel = "stylesheet" href =
"assets/style.css">
< script type = "text/javascript" src =
"assets/highlight-lisp.js">
< / script >
< script type = "text/javascript" src =
"assets/jquery-3.2.1.min.js">
< / script >
< script type = "text/javascript" src =
"assets/jquery.toc/jquery.toc.min.js">
< / script >
< script type = "text/javascript" src =
"assets/toggle-toc.js">
< / script >
< link rel = "stylesheet" href =
"assets/github.css">
< link rel = "stylesheet" href = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity = "sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin = "anonymous" >
< / head >
< body >
< h1 id = "title-xs" > < a href = "index.html" > The Common Lisp Cookbook< / a > – Pattern Matching< / h1 >
< div id = "logo-container" >
< a href = "index.html" >
< img id = "logo" src = "assets/cl-logo-blue.png" / >
< / a >
< div id = "searchform-container" >
< form onsubmit = "duckSearch()" action = "javascript:void(0)" >
< input id = "searchField" type = "text" value = "" placeholder = "Search..." >
< / form >
< / div >
< div id = "toc-container" class = "toc-close" >
< div id = "toc-title" > Table of Contents< / div >
< ul id = "toc" class = "list-unstyled" > < / ul >
< / div >
< / div >
< div id = "content-container" >
< h1 id = "title-non-xs" > < a href = "index.html" > The Common Lisp Cookbook< / a > – Pattern Matching< / h1 >
<!-- Announcement we can keep for 1 month or more. I remove it and re - add it from time to time. -->
< p class = "announce" >
📹 < a href = "https://www.udemy.com/course/common-lisp-programming/?couponCode=6926D599AA-LISP4ALL" > NEW! Learn Lisp in videos and support our contributors with this 40% discount.< / a >
< / p >
< p class = "announce-neutral" >
📕 < a href = "index.html#download-in-epub" > Get the EPUB and PDF< / a >
< / p >
< div id = "content"
< p > The ANSI Common Lisp standard does not include facilities for pattern
matching, but libraries existed for this task and
< a href = "https://github.com/guicho271828/trivia" > Trivia< / a > became a community
standard.< / p >
< p > For an introduction to the concepts of pattern matching, see < a href = "https://github.com/guicho271828/trivia/wiki/What-is-pattern-matching%3F-Benefits%3F" > Trivia’ s wiki< / a > .< / p >
< p > Trivia matches against < em > a lot< / em > of lisp objects and is extensible.< / p >
< p > The library is in Quicklisp:< / p >
< pre > < code class = "language-lisp" > (ql:quickload "trivia")
< / code > < / pre >
< p > For the following examples, let’ s < code > use< / code > the library:< / p >
< pre > < code class = "language-lisp" > (use-package :trivia)
< / code > < / pre >
< h2 id = "common-destructuring-patterns" > Common destructuring patterns< / h2 >
< h3 id = "cons" > < code > cons< / code > < / h3 >
< pre > < code class = "language-lisp" > (match '(1 2 3)
((cons x y)
; ^^ pattern
(print x)
(print y)))
;; |-> 1
;; |-> (2 3)
< / code > < / pre >
< h3 id = "list-list" > < code > list< / code > , < code > list*< / code > < / h3 >
< p > < code > list< / code > is a strict pattern, it expects the length of the matched
object to be the same length as its subpatterns.< / p >
< pre > < code class = "language-lisp" > (match '(something 2 3)
((list a b _)
(values a b)))
SOMETHING
2
< / code > < / pre >
< p > Without the < code > _< / code > placeholder, it would not match:< / p >
< pre > < code class = "language-lisp" > (match '(something 2 3)
((list a b)
(values a b)))
NIL
< / code > < / pre >
< p > The < code > list*< / code > pattern is flexible on the object’ s length:< / p >
< pre > < code class = "language-lisp" > (match '(something 2 3)
((list* a b)
(values a b)))
SOMETHING
(2 3)
< / code > < / pre >
< pre > < code class = "language-lisp" > (match '(1 2 . 3)
((list* _ _ x)
x))
3
< / code > < / pre >
< p > However pay attention that if < code > list*< / code > receives only one object, that
object is returned, regardless of whether or not it is a list:< / p >
< pre > < code class = "language-lisp" > (match #(0 1 2)
((list* a)
a))
#(0 1 2)
< / code > < / pre >
< p > This is related to the definition of < code > list*< / code > in the HyperSpec: http://clhs.lisp.se/Body/f_list_.htm.< / p >
< h3 id = "vector-vector" > < code > vector< / code > , < code > vector*< / code > < / h3 >
< p > < code > vector< / code > checks if the object is a vector, if the lengths are the
same, and if the contents matches against each subpatterns.< / p >
< p > < code > vector*< / code > is similar, but called a soft-match variant that allows if
the length is larger-than-equal to the length of subpatterns.< / p >
< pre > < code class = "language-lisp" > (match #(1 2 3)
((vector _ x _)
x))
;; -> 2
< / code > < / pre >
< pre > < code class = "language-lisp" > (match #(1 2 3 4)
((vector _ x _)
x))
;; -> NIL : does not match
< / code > < / pre >
< pre > < code class = "language-lisp" > (match #(1 2 3 4)
((vector* _ x _)
x))
;; -> 2 : soft match.
< / code > < / pre >
< pre > < code > < vector-pattern> : vector | simple-vector
bit-vector | simple-bit-vector
string | simple-string
base-string | simple-base-string | sequence
(< vector-pattern> & rest subpatterns)
< / code > < / pre >
< h3 id = "class-and-structure-pattern" > Class and structure pattern< / h3 >
< p > There are three styles that are equivalent:< / p >
< pre > < code class = "language-lisp" > (defstruct foo bar baz)
(defvar *x* (make-foo :bar 0 :baz 1)
(match *x*
;; make-instance style
((foo :bar a :baz b)
(values a b))
;; with-slots style
((foo (bar a) (baz b))
(values a b))
;; slot name style
((foo bar baz)
(values bar baz)))
< / code > < / pre >
< h3 id = "type-satisfies" > < code > type< / code > , < code > satisfies< / code > < / h3 >
< p > The < code > type< / code > pattern matches if the object is of type. < code > satisfies< / code > matches
if the predicate returns true for the object. A lambda form is
acceptable.< / p >
< h3 id = "assoc-property-alist-plist" > < code > assoc< / code > , < code > property< / code > , < code > alist< / code > , < code > plist< / code > < / h3 >
< p > All these patterns first check if the pattern is a list. If that is
satisfied, then they obtain the contents, and the value is matched
against the subpattern.< / p >
< h3 id = "array-simple-array-row-major-array-patterns" > Array, simple-array, row-major-array patterns< / h3 >
< p > See https://github.com/guicho271828/trivia/wiki/Type-Based-Destructuring-Patterns#array-simple-array-row-major-array-pattern !< / p >
< h2 id = "logic-based-patterns" > Logic based patterns< / h2 >
< p > We can combine any pattern with some logic.< / p >
< h3 id = "and-or" > < code > and< / code > , < code > or< / code > < / h3 >
< p > The following:< / p >
< pre > < code class = "language-lisp" > (match x
((or (list 1 a)
(cons a 3))
a))
< / code > < / pre >
< p > matches against both < code > (1 2)< / code > and < code > (4 . 3)< / code > and returns 2 and 4, respectively.< / p >
< h3 id = "not" > < code > not< / code > < / h3 >
< p > It does not match when subpattern matches. The variables used in the
subpattern are not visible in the body.< / p >
< h2 id = "guards" > Guards< / h2 >
< p > Guards allow us to use patterns < em > and< / em > to verify them against a predicate.< / p >
< p > The syntax is < code > guard< / code > + < code > subpattern< / code > + < code > a test form< / code > , and the body.< / p >
< pre > < code class = "language-lisp" > (match (list 2 5)
((guard (list x y) ; subpattern1
(= 10 (* x y))) ; test-form
:ok))
< / code > < / pre >
< p > If the subpattern is true, the test form is evaluated, and if it is
true it is matched against subpattern1.< / p >
< h2 id = "nesting-patterns" > Nesting patterns< / h2 >
< p > Patterns can be nested:< / p >
< pre > < code class = "language-lisp" > (match '(:a (3 4) 5)
((list :a (list _ c) _)
c))
< / code > < / pre >
< p > returns < code > 4< / code > .< / p >
< h2 id = "see-more" > See more< / h2 >
< p > See < a href = "https://github.com/guicho271828/trivia/wiki/Special-Patterns" > special patterns< / a > : < code > place< / code > , < code > bind< / code > and < code > access< / code > .< / p >
< p class = "page-source" >
Page source: < a href = "https://github.com/LispCookbook/cl-cookbook/blob/master/pattern_matching.md" > pattern_matching.md< / a >
< / p >
< / div >
< script type = "text/javascript" >
// Don't write the TOC on the index.
if (window.location.pathname != "/cl-cookbook/") {
$("#toc").toc({
content: "#content", // will ignore the first h1 with the site+page title.
headings: "h1,h2,h3,h4"});
}
$("#two-cols + ul").css({
"column-count": "2",
});
$("#contributors + ul").css({
"column-count": "4",
});
< / script >
< div >
< footer class = "footer" >
< hr / >
© 2002– 2021 the Common Lisp Cookbook Project
< / footer >
< / div >
< div id = "toc-btn" > T< br > O< br > C< / div >
< / div >
< script text = "javascript" >
HighlightLisp.highlight_auto({className: null});
< / script >
< script type = "text/javascript" >
function duckSearch() {
var searchField = document.getElementById("searchField");
if (searchField & & searchField.value) {
var query = escape("site:lispcookbook.github.io/cl-cookbook/ " + searchField.value);
window.location.href = "https://duckduckgo.com/?kj=b2& kf=-1& ko=1& q=" + query;
// https://duckduckgo.com/params
// kj=b2: blue header in results page
// kf=-1: no favicons
}
}
< / script >
< script async defer data-domain = "lispcookbook.github.io/cl-cookbook" src = "https://plausible.io/js/plausible.js" > < / script >
< / body >
< / html >