Шаблоны в стиле обратной кавычки
В этом подразделе описываются шаблоны в стиле обратной кавычки, набор встроенных шаблонов, которые упрощают структурное сопоставление. Для справки, см. Условное сопоставление шаблонов.
Шаблоны в стиле обратной кавычки — это мощный набор pcase расширений шаблонов (созданных с использованием pcase-defmacro), которые позволяют легко сопоставлять expval со спецификациями его структуры.
Например, чтобы сопоставить expval, который должен быть списком из двух элементов, первым из которых является определенная строка, а второй — любое значение, можно записать базовый шаблон:
(and (pred listp)
ls
(guard (= 2 (length ls)))
(guard (string= "first" (car ls)))
(let second-elem (cadr ls)))
или можно записать эквивалентный шаблон в стиле обратной кавычки:
`("first" ,second-elem)
Шаблон в стиле обратной кавычки более лаконичен, похож на структуру expval и избегает привязки ls.
Шаблон в стиле обратной кавычки имеет вид `qpat, где qpat может иметь следующие формы:
(qpat1 . qpat2)-
Сопоставляется, если expval является ячейкой конса,
carкоторой соответствует qpat1, аcdrкоторой соответствует qpat2. Это легко обобщается на списки, как в(qpat1 qpat2 …). [qpat1 qpat2 … qpatm]-
Сопоставляется, если expval является вектором длины m,
0..(m-1)элементы которого соответствуют qpat1, qpat2 … qpatm соответственно. symbolkeywordnumberstring-
Сопоставляется, если соответствующий элемент expval равен
equalуказанному литеральному объекту. ,patternСопоставляется, если соответствующий элемент expval соответствует шаблону pattern. Обратите внимание, что pattern — это любой тип, который
pcaseподдерживает. (В примере вышеsecond-elem— это базовый шаблон symbol; поэтому он соответствует чему угодно и выполняет привязкуsecond-elem.)
Соответствующий элемент — это часть expval, которая находится в той же структурной позиции, что и qpat в шаблоне в стиле обратной кавычки. (В примере выше соответствующий элемент second-elem — это второй элемент expval.)
Вот пример использования pcase для реализации простого интерпретатора небольшого языка выражений (обратите внимание, что это требует лексической привязки для лямбда-выражения в fn разделе, чтобы правильно захватить body и arg (см. Лексическую привязку):
(defun evaluate (form env)
(pcase form
(`(add ,x ,y) (+ (evaluate x env)
(evaluate y env)))
(`(call ,fun ,arg) (funcall (evaluate fun env)
(evaluate arg env)))
(`(fn ,arg ,body) (lambda (val)
(evaluate body (cons (cons arg val)
env))))
((pred numberp) form)
((pred symbolp) (cdr (assq form env)))
(_ (error "Syntax error: %S" form))))
Первые три правила используют шаблоны в стиле обратной кавычки. `(add ,x ,y) — это шаблон, который проверяет, что form является списком из трёх элементов, начинающимся с литерального символа add, затем извлекает второй и третий элементы и привязывает их к символам x и y соответственно. Тело правила вычисляет x и y и складывает результаты. Аналогично, правило call реализует вызов функции, а правило fn реализует определение анонимной функции.
Остальные правила используют базовые шаблоны. (pred numberp) сопоставляется, если form является числом. При совпадении тело вычисляет его. (pred symbolp) сопоставляется, если form является символом. При совпадении тело ищет символ в env и возвращает его ассоциацию. Наконец, _ — это универсальный шаблон, который соответствует любому значению, поэтому он подходит для сообщения об ошибках синтаксиса.
Вот несколько примеров программ на этом небольшом языке, включая результаты их оценки:
(evaluate '(add 1 2) nil) ⇒ 3 (evaluate '(add x y) '((x . 1) (y . 2))) ⇒ 3 (evaluate '(call (fn x (add 1 x)) 2) nil) ⇒ 3 (evaluate '(sub 1 2) nil) ⇒ error
Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Backquote-Patterns.html