Это предыдущая редакция документации. Чтобы создать счётчики с отдельным или общим состоянием, откройте актуальное руководство «Замыкания и состояние счётчиков».
Замыкание позволяет функции сохранять окружение, в котором она была создана. Это руководство показывает, как устроено замыкание и где оно полезно.
Что такое замыкание?
Простыми словами, замыкание это функция, объединенная со своим «рюкзаком». Этот рюкзак содержит все переменные, которые были в области видимости в момент создания функции.
Это означает, что функция может получить доступ к этим «запомненным» переменным, даже если она вызывается из совершенно другой части вашей программы.
Давайте рассмотрим это на самом распространенном паттерне: «фабрика функций».
Паттерн «Фабрика функций»
Представьте, что вам нужно много функций, которые делают похожие вещи. Например, одна функция, которая добавляет 5 к числу, другая, которая добавляет 10, и еще одна, которая добавляет 100. Вместо того чтобы писать каждую вручную, вы можете создать «фабрику», которая будет производить эти функции для вас.
Шаг 1: Напишите фабричную функцию
Наша фабрика, make-adder, будет принимать один аргумент, amount-to-add, и её задача состоит в том, чтобы возвращать новую функцию.
(define (make-adder amount-to-add)
(lambda (n)
(+ n amount-to-add)))Шаг 2: «Магия» замыкания
Когда мы вызываем (make-adder 5), вот что происходит:
- Для вызова
make-adderсоздается новое, временное окружение. - Внутри этого окружения параметр
amount-to-addпривязывается к значению5. - Создается функция
lambda. При своем создании она «осматривается» и упаковывает все переменные, которые видит, в свой «рюкзак». Она видит, чтоamount-to-addравен5, и сохраняет эту информацию. make-adderзавершает работу и возвращает функциюlambdaвместе с ее рюкзаком, содержащимamount-to-add = 5.
Эта возвращённая функция, лямбда вместе со своим рюкзаком, и есть замыкание.
Шаг 3: Используйте созданные функции
Теперь мы можем создавать специализированные функции с помощью нашей фабрики:
;; Создаем функцию, которая всегда будет добавлять 5.
(define add-five (make-adder 5))
;; Создаем функцию, которая всегда будет добавлять 10.
(define add-ten (make-adder 10))
;; Давайте их используем!
(add-five 100)
;; Результат: 105
;; Функция `add-five` заглядывает в свой «рюкзак» и вспоминает, что
;; `amount-to-add` был равен 5.
(add-ten 100)
;; Результат: 110
;; У функции `add-ten` есть свой собственный, отдельный рюкзак, где
;; `amount-to-add` был равен 10.Почему это полезно?
Этот паттерн невероятно мощный. Он позволяет вам создавать на лету настраиваемые, предварительно сконфигурированные функции. Вы можете использовать его для:
- Создания настраиваемых обработчиков событий.
- Настройки функций с начальным состоянием.
- Продвинутых паттернов, таких как каррирование и частичное применение.
Заключение
Понимание замыканий помогает писать функциональный код в Lispex. Коротко: это функция + окружение при создании.
Более формальное определение находится в текущем руководстве Процедуры и замыкания.