Racket - Closure / Currying, в чем разница? - PullRequest
1 голос
/ 21 июня 2020

Итак, из моих личных исследований кажется, что замыкания / каррирование кажутся более или менее одним и тем же, что не может быть очевидно правильным. Итак, в чем разница?

Вот пример закрытия в Racket:

(define (make-an-adder x)
  (lambda (y)
    (+ y x)))

(define add3 (make-an-adder 3))


(add3 5)

вернет

8

Итак, в чем разница между карри? Потому что, если я посмотрю документацию и другие примеры, мне покажется, что они делают то же самое, что я показал для закрытия?

Всем заранее спасибо!

1 Ответ

3 голосов
/ 21 июня 2020

Итак, это разные концепции, но оба связаны с вложенными лямбдами.

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

Это закрытие, но не пример каррирования.

...