Иногда полезно отложить оценку выражения, например, если вы хотите избежать выполнения длительного вычисления, если в дальнейшем в программе окажется, что результат не нужен. Библиотека thunk предоставляет следующие функции и макросы для поддержки такой отложенной оценки:
Возвращает thunk для оценки forms. Thunk — это замыкание (см. Closures), которое наследует лексическую среду вызова thunk-delay. Использование этого макроса требует lexical-binding.
Принудительно выполняет thunk оценку форм, указанных в thunk-delay, который создал thunk. Возвращается результат оценки последней формы. thunk также «запоминает», что он был принужден: любые дальнейшие вызовы thunk-force с тем же thunk просто вернут тот же результат, не выполняя формы повторно.
Этот макрос аналогичен let, но создает «ленивые» привязки переменных. Каждая привязка имеет вид (symbol value-form). В отличие от let, оценка любой value-form откладывается до первого использования привязки соответствующего symbol при оценке forms. Любая value-form оценивается не более одного раза. Использование этого макроса требует 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, но любое выражение в bindings может ссылаться на предыдущие привязки в этой форме 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, оборачивающими выражения привязки. Все ссылки на исходные переменные в теле forms затем заменяются выражением, которое вызывает thunk-force с соответствующей вспомогательной переменной в качестве аргумента. Таким образом, любой код, использующий thunk-let или thunk-let*, можно переписать с использованием thunks, но во многих случаях использование этих макросов приводит к более чистому коду, чем явное использование thunks.