标准的 Common Lisp 没有提供模式匹配,但是社区提供了一个 Trivia 库,参考 Trivia’s wiki

通过 quicklisp 加载

  1. (ql:quickload :trivia)
  2. (use-package :trivia)

通用结构模式

cons

  1. (match '(1 2 3)
  2. ((cons x y)
  3. ; ^^ pattern
  4. (print x)
  5. (print y)))
  6. ;; |-> 1
  7. ;; |-> (2 3)

list, list*

  1. (match '(something #(0 1 2))
  2. ((list a (vector 0 _ b))
  3. (value a b)))
  4. SOMETHING
  5. 2
  6. (match '(1 2 . 3)
  7. ((list* _ _ x)
  8. x))
  9. 3

vector, vector*

  1. (match #(1 2 3)
  2. ((vector _ x _)
  3. x))
  4. ;; -> 2
  5. (match #(1 2 3 4)
  6. ((vector _ x _)
  7. x))
  8. ;; -> NIL : does not match
  9. (match #(1 2 3 4)
  10. ((vector* _ x _)
  11. x))
  12. ;; -> 2 : soft match.
  1. <vector-pattern> : vector | simple-vector
  2. bit-vector | simple-bit-vector
  3. string | simple-string
  4. base-string | simple-base-string | sequence
  5. (<vector-pattern> &rest subpatterns)

类别即结构模式

  1. (defstruct foo bar baz)
  2. (defvar *x* (make-foo :bar 0 :baz 1)
  3. (match *x*
  4. ;; make-instance style
  5. ((foo :bar a :baz b)
  6. (values a b))
  7. ;; with-slots style
  8. ((foo (bar a) (baz b))
  9. (values a b))
  10. ;; slot name style
  11. ((foo bar baz)
  12. (values bar baz)))

type, satisfies

type 匹配对象的类型,satisfies 返回断言正确的对象,可以接受 lambda 函数。

assoc, property, alist, plist

会先检查是否是列表,然后在对列表里面的内容进行匹配

Array, simple-array, row-major-array 匹配

参见:https://github.com/guicho271828/trivia/wiki/Type-Based-Destructuring-Patterns#array-simple-array-row-major-array-pattern

逻辑匹配

and, or

  1. (match x
  2. ((or (list 1 a)
  3. (cons a 3))
  4. a)

能够同时匹配 (1 2), (4 . 3),返回 2 和 4.

not

返回不匹配的值

guards

语法是 guard + subpattern + a test form 然后是主体

  1. (match (list 2 5)
  2. ((guard (list x y) ; subpattern
  3. (= 10 (* x y)) ; test-form
  4. (- x y) (satisfies evenp)) ; generator1, subpattern1
  5. t))

如果 subpattern 为真,执行测试语句,若测试语句也为真,执行 subpattern1。
返回 nil,因为 (- x y) == 3 不满足 evenp

嵌套匹配

  1. (match '(:a (3 4) 5)
  2. ((list :a (list _ c) _)
  3. c))

结果返回 4

拓展阅读

参见 special patternsplacebindaccess