所以它们是不同的概念,但都与嵌套的 lambdas 相关。
闭包可以由 lambda 创建,该 lambda 引用定义在自身外部的变量,并且当 lambda 从定义该外部变量的上下文中转义时最重要。闭包的工作是确保在 lambda 转义该上下文时保留该变量。
Curried 函数是一个可以在多个步骤或多个不同的函数应用程序中获取其参数的函数。这通常意味着 lambdas 中嵌套了 lambdas。
柯里化函数并不总是闭包,尽管它们通常是
大多数有用的柯里化函数都需要使用闭包,但如果内部 lambda 忽略外部参数,它们就不是闭包。一个简单的例子:
(define (curried-ignore-first ignored)
(lambda (y) y))
这不是一个闭包,因为内部 lambda (lambda (y) y) 已经关闭:它不引用自身外部的任何变量。
柯里化函数并不总是需要忽略外部参数...它只需要在返回内部 lambda 之前完成处理它们,这样内部 lambda 就不会引用外部参数。一个简单的例子是 curried choose 函数。 choose 的“正常”定义确实使用了闭包:
(define (choose b)
(lambda (x y)
(if b x y))) ; inner lambda refers to `b`, so it needs a closure
但是,如果将if b 放在外部 lambda 之外,我们可以避免进行闭包:
(define (choose b)
(if b
(lambda (x y) x) ; not closures, just nested lambdas
(lambda (x y) y)))
闭包并不总是来自柯里化函数
当内部 lambda 引用外部上下文中的变量并可能转义该上下文时,需要闭包。外部上下文通常是函数或 lambda,但不一定是。它可以是一个让:
(define closure-with-let
(let ([outer "outer"])
(lambda (ignored) outer))) ; closure because it refers to `outer`
这是一个闭包,但不是柯里化的例子。
将 Curried-function-produce-a-closure 变成一个没有闭包的函数
原始问题中的示例是一个产生闭包的柯里化函数
(define (make-an-adder x)
(lambda (y)
(+ y x)))
如果您想创建一个仍然是具有相同行为的柯里化函数的版本,但在某些特殊情况下不需要关闭 x,您可以在 lambda 之前的那些上进行分支:
(define (make-an-adder x)
(match x
[0 identity]
[1 add1]
[-1 sub1]
[2 (lambda (y) (+ y 2))]
[3 (lambda (y) (+ y 3))]
[_ (lambda (y) (+ y x))]))
这避免了在 x 是精确整数 -1 到 3 的情况下生成闭包,但在 x 的所有其他情况下仍会生成闭包。如果您将x 的域限制为有限集,您可以将其变成不需要闭包的函数,只需枚举所有情况即可。
如果您不希望在x 上进行闭包,但对其他事物的闭包没问题,您可以使用递归和组合来构造一个不会在x 上关闭的输出函数:
(define (make-an-adder x)
(cond [(zero? x) identity]
[(positive-integer? x)
(compose add1 (make-an-adder (sub1 x)))]
[(negative-integer? x)
(compose sub1 (make-an-adder (add1 x)))]))
请注意,这仍然会产生闭包(因为compose 在其参数上创建了闭包),但它产生的函数不会在x 上关闭。一旦这个版本的make-an-adder 产生了它的结果,它就“完成”了处理x 并且不再需要关闭它了。