Отложенная и ленивая оценка
Иногда полезно отложить оценку выражения, например, если вы хотите избежать выполнения длительных вычислений, если выяснится, что результат в дальнейшем не нужен программе. Библиотека 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