Как замыкания используются в функциональных языках - PullRequest
3 голосов
/ 14 января 2010

По какой-то причине я склонен связывать замыкания с функциональными языками. Я полагаю, что это в основном потому, что обсуждения, которые я видел по поводу замыканий, почти всегда происходят в среде, сфокусированной на функциональном программировании. При этом фактическое практическое использование замыканий, которые, как я могу себе представить, являются нефункциональными по своей природе.

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

Изменить: Я должен уточнить, что я ссылаюсь на фактические функциональные языки, то есть я искал использования, которые сохраняют ссылочную прозрачность (для того же ввода вы получаете тот же вывод).

Редактировать: добавление сводки того, что было опубликовано до сих пор:

  1. Закрытия используются для частичной оценки. В частности, для функции, которая принимает два аргумента, ее можно вызвать с одним аргументом, в результате чего она возвращает функцию, которая принимает один аргумент. Обычно метод, с помощью которого эта вторая функция «сохраняет» первое переданное ей значение, является замыканием.
  2. Объекты могут быть реализованы с помощью замыканий. Возвращается функция, которая закрывает несколько переменных и может использовать их как атрибуты объекта. Сама функция может возвращать больше методов, которые действуют как методы объекта, которые также имеют доступ к этим переменным. Предполагая, что переменные не изменены, ссылочная прозрачность сохраняется.

Ответы [ 4 ]

6 голосов
/ 14 января 2010

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

Самый вездесущий пример:

var generateId = function() {
    var id = 0;
    return function() {
        return id++;
    }
}();
window.alert(generateId());
window.alert(generateId());

Но это привет, мир закрытий Javascript. Однако есть еще много практических применений.

В последнее время на работе мне нужно было написать простую фотогалерею с помощью ползунков. Это делает что-то вроде:

var slide = function() {
    var photoSize = ...
    var ... // lots of calculations of sizes, distances to scroll, etc
    var scroll = function(direction, amout) {
        // here we use some of the variables defined just above
        // (it will be returned, therefore it is a closure)
    };
    return {
        up: function() { scroll(1, photoSize); },
        down: function() { scroll(-1, photoSize); }
    }
}();

slide.up();
// actually the line above would have to be associated to some
// event handler to be useful

В этом случае я использовал замыкания, чтобы скрыть всю логику прокрутки вверх и вниз и получить код, который очень семантический: в Javascript "сдвиньте" напишу slide.up().

3 голосов
/ 15 января 2010

Они используются для многих вещей. Возьмем, к примеру, функцию композиции:

let compose f g = fun x -> f (g x)

Возвращает замыкание, использующее аргументы из функциональной среды, в которой оно было создано. Функциональные языки, такие как OCaml и Haskell, фактически неявно используют замыкания повсюду. Например:

let flip f a b = f b a

Обычно это будет вызываться как let minusOne = flip (-) 1, чтобы создать функцию, которая вычтет 1 из своего аргумента. Эта «частично примененная» функция фактически аналогична следующей:

let flip f a = fun b -> f b a

Возвращает замыкание, которое запоминает два переданных вами аргумента и принимает другой собственный аргумент.

3 голосов
/ 14 января 2010

Одно хорошее применение для замыканий - создание таких вещей, как деревья решений. Вы возвращаете функцию classify (), которая проверяет, идти ли вниз по левому или правому дереву, а затем вызывает ее функцию leftClassify () или rightClassify () в зависимости от входных данных. Листовые функции просто возвращают метку класса. Я на самом деле реализовал деревья решений в Python и D таким образом раньше.

1 голос
/ 15 января 2010

Замыкания могут использоваться для имитации объектов, которые могут отвечать на сообщения и поддерживать свое собственное локальное состояние. Вот простой объект счетчика на схеме:

;; counter.ss
;; A simple counter that can respond to the messages
;; 'next and 'reset.  

(define (create-counter start-from)
  (let ((value start-from))
    (lambda (message)
      (case message
    ((next) (set! value (add1 value)) value)
    ((reset) (set! value start-from))
    (else (error "Invalid message!"))))))

Пример использования:

> (load "counter.ss")
> (define count-from-5 (create-counter 5))
> (define count-from-0 (create-counter 0))
> (count-from-5 'next)
6
> (count-from-5 'next)
7
> (count-from-0 'next)
1
> (count-from-0 'next)
2
> (count-from-0 'reset)
> (count-from-0 'next)
1
...