Spec-Zone.ru › Elisp

Отложенная и ленивая оценка

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

Макрос: thunk-delay формы…

Возвращает thunk для оценки форм. Thunk — это замыкание (см. Замыкания), которое наследует лексическую среду вызова thunk-delay. Использование этого макроса требует lexical-binding.

Функция: thunk-force thunk

Вынуждает thunk выполнить оценку форм, указанных в thunk-delay, которые создали thunk. Возвращается результат оценки последней формы. Thunk также «запоминает», что он был принудительно вычислен: любые последующие вызовы thunk-force со тем же thunk просто вернут тот же результат, не оценивая формы повторно.

Макрос: thunk-let (связывания…) формы…

Этот макрос аналогичен let, но создаёт «ленивые» привязки переменных. Любое связывание имеет вид (symbol value-form). В отличие от let, вычисление любого значение-формы откладывается до тех пор, пока привязка соответствующего символа не будет использована в первый раз при оценке форм. Любое значение-формы вычисляется не более одного раза. Использование этого макроса требует lexical-binding.

Пример:

(defun f (number)
  (thunk-let ((derived-number
              (progn (message "Calculating 1 plus 2 times %d" number)
                     (1+ (* 2 number)))))
    (if (> number 10)
        derived-number
      number)))
(f 5)
⇒ 5
(f 12)
-| Calculating 1 plus 2 times 12
⇒ 25

Из-за специфики лениво связанных переменных, их установка (например, с помощью setq) является ошибкой.

Макрос: thunk-let* (связывания…) формы…

Это как thunk-let, но любое выражение в связываниях разрешается ссылаться на предыдущие привязки в этом thunk-let* форме. Использование этого макроса требует lexical-binding.

(thunk-let* ((x (prog2 (message "Calculating x...")
                    (+ 1 1)
                  (message "Finished calculating x")))
             (y (prog2 (message "Calculating y...")
                    (+ x 1)
                  (message "Finished calculating y")))
             (z (prog2 (message "Calculating z...")
                    (+ y 1)
                  (message "Finished calculating z")))
             (a (prog2 (message "Calculating a...")
                    (+ z 1)
                  (message "Finished calculating a"))))
  (* z x))

-| Calculating z...
-| Calculating y...
-| Calculating x...
-| Finished calculating x
-| Finished calculating y
-| Finished calculating z
⇒ 8

thunk-let и thunk-let* неявно используют thunks: их расширение создаёт вспомогательные символы и привязывает их к thunks, обернутым вокруг выражений привязки. Все ссылки на исходные переменные в теле форм затем заменяются выражением, которое вызывает thunk-force со соответствующей вспомогательной переменной в качестве аргумента. Таким образом, любой код, использующий thunk-let или thunk-let*, можно было бы переписать с использованием thunks, но во многих случаях использование этих макросов приводит к более удобочитаемому коду, чем явное использование thunks.

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/Deferred-Eval.html

Spec-Zone.ru

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