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