标准的 Common Lisp 没有提供模式匹配,但是社区提供了一个 Trivia 库,参考 Trivia’s wiki
通过 quicklisp 加载
(ql:quickload :trivia)
(use-package :trivia)
通用结构模式
cons
(match '(1 2 3)
((cons x y)
; ^^ pattern
(print x)
(print y)))
;; |-> 1
;; |-> (2 3)
list
, list*
(match '(something #(0 1 2))
((list a (vector 0 _ b))
(value a b)))
SOMETHING
2
(match '(1 2 . 3)
((list* _ _ x)
x))
3
vector
, vector*
(match #(1 2 3)
((vector _ x _)
x))
;; -> 2
(match #(1 2 3 4)
((vector _ x _)
x))
;; -> NIL : does not match
(match #(1 2 3 4)
((vector* _ x _)
x))
;; -> 2 : soft match.
<vector-pattern> : vector | simple-vector
bit-vector | simple-bit-vector
string | simple-string
base-string | simple-base-string | sequence
(<vector-pattern> &rest subpatterns)
类别即结构模式
(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)))
type
, satisfies
type
匹配对象的类型,satisfies
返回断言正确的对象,可以接受 lambda 函数。
assoc
, property
, alist
, plist
会先检查是否是列表,然后在对列表里面的内容进行匹配
Array, simple-array, row-major-array 匹配
逻辑匹配
and
, or
(match x
((or (list 1 a)
(cons a 3))
a)
能够同时匹配 (1 2)
, (4 . 3)
,返回 2 和 4.
not
返回不匹配的值
guards
语法是 guard
+ subpattern
+ a test form
然后是主体
(match (list 2 5)
((guard (list x y) ; subpattern
(= 10 (* x y)) ; test-form
(- x y) (satisfies evenp)) ; generator1, subpattern1
t))
如果 subpattern 为真,执行测试语句,若测试语句也为真,执行 subpattern1。
返回 nil
,因为 (- x y) == 3
不满足 evenp
嵌套匹配
(match '(:a (3 4) 5)
((list :a (list _ c) _)
c))
结果返回 4
。
拓展阅读
参见 special patterns:place
,bind
和 access
。