Замыкание (программирование)

В информатике закрытие - это функция, которая имеет собственную среду. В этой среде есть по крайней мере одна связанная переменная (имя, имеющее значение, например, число). Среда замыкания хранит связанные переменные в памяти между использованиями замыкания.

Питер Дж. Ландин дал этой идее название "замыкание" в 1964 году. Язык программирования Scheme сделал замыкания популярными после 1975 года. Многие языки программирования, созданные после этого времени, имеют замыкания.

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

Замыкания и первоклассные функции

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

Например, посмотрите на следующую функцию Scheme:

; Возвращает список всех книг, у которых продано не менее ПОРОГОВОГО количества экземпляров. (define (best-selling-books threshold) (filter (lambda (book) (>= (book-sales book) threshold)) book-list))

В этом примере лямбда-выражение (лямбда (книга) (>= (book-sales book) threshold)) является частью функции best-selling-books. Когда функция выполняется, Scheme должна сделать значение лямбды. Для этого она создает закрытие с кодом лямбды и ссылкой на переменную threshold, которая является свободной переменной внутри лямбды. (Свободная переменная - это имя, не связанное со значением).

Затем функция filter выполняет закрытие для каждой книги в списке, чтобы выбрать, какие книги следует вернуть. Поскольку в самом закрытии есть ссылка на порог, закрытие может использовать это значение каждый раз, когда filter выполняет закрытие. Сама функция filter может быть написана в совершенно отдельном файле.

Вот тот же пример, переписанный на ECMAScript (JavaScript), другом популярном языке с поддержкой замыканий:

// Возвращает список всех книг, проданных не менее 'порогового' количества экземпляров. function bestSellingBooks(threshold) { return bookList. filter( function(book) { return book. sales >= threshold; }     ); }

ECMAScript использует здесь слово function вместо lambda, а метод Array.filter вместо функции filter, но в остальном код выполняет те же действия тем же способом.

Функция может создавать закрытие и возвращать его. Следующий пример представляет собой функцию, которая возвращает функцию.

В схеме:

; Возвращаем функцию, которая аппроксимирует производную f ; используя интервал dx, который должен быть соответственно мал. (define (derivative f dx) (lambda (x) (/ (- (f (+ x dx))) (f x)) dx))))

В ECMAScript:

// Возвращаем функцию, которая аппроксимирует производную от f // используя интервал dx, который должен быть соответственно мал. function derivative(f, dx) { return function(x) { return (f(x + dx) - f(x)) / dx; }; }

Среда замыкания сохраняет связанные переменные f и dx после возвращения объемлющей функции (производной). В языках без закрытий эти значения были бы потеряны после возвращения закрывающей функции. В языках с замыканиями связанная переменная должна храниться в памяти до тех пор, пока она есть у любого замыкания.

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

# Возвращаем функцию, которая аппроксимирует производную f # с помощью интервала dx, который должен быть соответственно мал. def derivative(f, dx): def gradient(x): return (f(x + dx) - f(x)) / dx return gradient

В этом примере функция с именем gradient образует замыкание вместе с переменными f и dx. Внешняя объемлющая функция с именем derivative возвращает это замыкание. В данном случае подойдет и анонимная функция.

def derivative(f, dx): return lambda x: (f(x + dx) - f(x)) / dx

В Python часто приходится использовать именованные функции, потому что его лямбда-выражения могут содержать только другие выражения (код, возвращающий значение), но не утверждения (код, имеющий эффекты, но не значение). Но в других языках, таких как Scheme, весь код возвращает значение; в Scheme все является выражением.

Использование замыканий

Заглушки имеют множество применений:

  • Разработчики программных библиотек могут позволить пользователям настраивать поведение, передавая замыкания в качестве аргументов важным функциям. Например, функция, сортирующая значения, может принимать аргумент замыкания, который сравнивает значения, подлежащие сортировке, в соответствии с заданным пользователем критерием.
  • Поскольку закрытия откладывают оценку - т.е. они ничего не "делают", пока их не вызовут - их можно использовать для определения управляющих структур. Например, все стандартные управляющие структуры Smalltalk, включая ветвления (if/then/else) и циклы (while и for), определяются с помощью объектов, методы которых принимают замыкания. Пользователи могут легко определять и свои собственные управляющие структуры.
  • Можно создать несколько функций, которые замыкаются на одной и той же среде, что позволяет им общаться в частном порядке, изменяя эту среду (в языках, позволяющих задавать ее).

В схеме

(define foo #f) (define bar #f) (let ((secret-message "none")) (set! foo (lambda (msg) (set! secret-message msg))) (set! bar (lambda () secret-message))) (display (bar)) ; печатает "none" (newline) (foo "meet me by the docks at midnight") (display (bar)) ; печатает "meet me by the docks at midnight".
  • Закрытия можно использовать для реализации объектных систем.

Примечание: Некоторые специалисты называют закрытием любую структуру данных, связывающую лексическое окружение, но обычно этот термин относится именно к функциям.

Вопросы и ответы

В: Что такое замыкание в информатике?


О: Замыкание - это функция, которая имеет собственное окружение.

В: Что содержит среда замыкания?


О: Среда замыкания содержит по крайней мере одну связанную переменную.

В: Кто дал название идее замыкания?


О: Питер Дж. Ландин дал название идее замыкания в 1964 году.

В: Какой язык программирования сделал замыкания популярными после 1975 года?


О: Язык программирования Scheme сделал замыкания популярными после 1975 года.

В: Являются ли анонимные функции и замыкания одним и тем же?


О: Анонимные функции иногда ошибочно называют замыканиями, но не все анонимные функции являются замыканиями.

В: Что делает анонимную функцию замыканием?


О: Анонимная функция является замыканием, если у нее есть собственное окружение с хотя бы одной связанной переменной.

В: Является ли именованное закрытие анонимным?


О: Нет, именованное закрытие не является анонимным.

AlegsaOnline.com - 2020 / 2023 - License CC3