Итак, это разные концепции, но оба связаны с вложенными лямбдами.
Замыкание может быть создано с помощью лямбда, который ссылается на переменную, определенную вне себя, и это наиболее важно, когда лямбда ускользает от контекст, в котором определена эта внешняя переменная. Задача Closure - обеспечить сохранение переменной, когда лямбда выходит из этого контекста.
Функция Curried - это функция, которая может принимать свои аргументы в несколько шагов или в несколько различных приложений-функций. Обычно это означает, что внутри лямбда-выражений вложены лямбды.
Каррированные функции не всегда являются закрытием, хотя они часто являются внешние аргументы, они не закрытие. Простой пример: (define (curried-ignore-first ignored)
(lambda (y) y))
Это не закрытие, потому что внутренняя лямбда (lambda (y) y)
уже закрыта: она не ссылается ни на какие внешние переменные. Каррированная функция не работает. Не всегда нужно игнорировать внешние аргументы ... просто нужно завершить их обработку, прежде чем она вернет внутреннюю лямбду, чтобы внутренняя лямбда не ссылалась на внешний аргумент. Простым примером этого является каррированная функция choose
. «Нормальное» определение choose
действительно использует закрытие: (define (choose b)
(lambda (x y)
(if b x y))) ; inner lambda refers to `b`, so it needs a closure
Однако, если if b
помещается за пределы внешней лямбды, мы можем избежать замыканий: (define (choose b)
(if b
(lambda (x y) x) ; not closures, just nested lambdas
(lambda (x y) y)))
Замыкания не всегда из каррированных функций
Замыкание необходимо, когда внутренняя лямбда ссылается на переменную во внешнем контексте и может выйти из этого контекста. Этот внешний контекст часто является функцией или лямбда, но это не обязательно. Это может быть let:
(define closure-with-let
(let ([outer "outer"])
(lambda (ignored) outer))) ; closure because it refers to `outer`
Это закрытие, но не пример каррирования.