Spec-Zone.ru › Elisp

Деструктуризация с помощью шаблонов pcase

Шаблоны pcase не только задают условие на форму объектов, которым они могут соответствовать, но и позволяют извлекать подчинённые поля этих объектов. Например, с помощью следующего кода можно извлечь 2 элемента из списка, являющегося значением переменной my-list:

  (pcase my-list
    (`(add ,x ,y)  (message "Contains %S and %S" x y)))

Так будут извлечены не только x и y, но также проверено, что my-list — это список, содержащий ровно 3 элемента, первый из которых является символом add. Если какая-либо из этих проверок не пройдёт, pcase немедленно вернёт nil, не вызывая message.

Извлечение нескольких значений, хранящихся в объекте, называется деструктуризацией. Шаблоны pcase позволяют выполнять деструктурирующее связывание, которое похоже на локальное связывание (см. Локальные переменные), но присваивает значения нескольким элементам переменной, извлекая эти значения из объекта совместимой структуры.

Макросы, описанные в этом разделе, используют шаблоны pcase для выполнения деструктурирующего связывания. Требование совместимости структуры объекта означает, что объект должен соответствовать шаблону, поскольку только в этом случае можно извлечь его подчинённые поля. Например:

  (pcase-let ((`(add ,x ,y) my-list))
    (message "Contains %S and %S" x y))

делает то же, что и предыдущий пример, за исключением того, что сразу пытается извлечь x и y из my-list, не проверяя предварительно, является ли my-list списком с нужным числом элементов и содержит ли он add в качестве первого элемента.

Точное поведение в случае, если объект на самом деле не соответствует шаблону, зависит от типов, однако тело не будет молча пропущено: либо выдаётся ошибка, либо тело выполняется, причём некоторые переменные связываются с произвольными значениями, например nil. Например, в приведённом выше шаблоне x и y извлекаются с помощью таких операций, как car или nth, поэтому, если my-list слишком короток, они получат значение nil. Напротив, для шаблона вида `[add ,x ,y] те же переменные извлекались бы с помощью aref, которая выдала бы ошибку, если my-list не является массивом или слишком короток.

Для деструктурирующего связывания обычно подходят шаблоны pcase, описанные в разделе Шаблоны в стиле обратных кавычек, поскольку они задают структуру объектов, которым будет соответствовать шаблон.

Об альтернативном средстве для деструктурирующего связывания см. seq-let.

Макрос: pcase-let bindings body…

Выполняет деструктурирующее связывание переменных согласно bindings, а затем вычисляет body.

bindings — это список связываний вида (pattern exp), где exp — вычисляемое выражение, а pattern — шаблон pcase.

Сначала вычисляются все выражения exp, после чего они сопоставляются с соответствующими шаблонами pattern, создавая новые связывания переменных, которые затем можно использовать внутри body. Связывания переменных создаются посредством деструктурирующего связывания элементов pattern со значениями соответствующих элементов вычисленного выражения exp.

Простой пример:

(pcase-let ((`(,major ,minor)
	     (split-string "image/png" "/")))
  minor)
     ⇒ "png"
Макрос: pcase-let* bindings body…

Выполняет деструктурирующее связывание переменных согласно bindings, а затем вычисляет body.

bindings — это список связываний вида (pattern exp), где exp — вычисляемое выражение, а pattern — шаблон pcase. Связывания переменных создаются посредством деструктурирующего связывания элементов pattern со значениями соответствующих элементов вычисленного выражения exp.

В отличие от pcase-let, но подобно let*, каждое выражение exp сопоставляется с соответствующим шаблоном pattern до обработки следующего элемента bindings. Поэтому связывания переменных, созданные в каждом элементе bindings, доступны в выражениях exp следующих элементов bindings, а также в body.

Макрос: pcase-dolist (pattern list) body…

Выполняет body один раз для каждого элемента list, на каждой итерации выполняя деструктурирующее связывание переменных в pattern со значениями соответствующих подчинённых полей элемента list. Связывание выполняется так же, как с помощью pcase-let. Если pattern — простая переменная, то в итоге это эквивалентно dolist (см. Итерация).

Макрос: pcase-setq pattern value…

Присваивает значения переменным в форме setq, деструктурируя каждое value согласно соответствующему pattern.

Макрос: pcase-lambda lambda-list &rest body

Похож на lambda, но позволяет задавать каждый аргумент в виде шаблона. Например, вот простая функция, принимающая в качестве аргумента cons-ячейку:

(setq fun
      (pcase-lambda (`(,key . ,val))
        (vector key (* val 10))))
(funcall fun '(foo . 2))
    ⇒ [foo 20]

Copyright © 1990-1996, 1998-2026 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Destructuring-with-pcase-Patterns.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API