gpt4 book ai didi

functional-programming - Racket - Closure/Currying,区别在哪里?

转载 作者:行者123 更新时间:2023-12-01 21:30:50 24 4
gpt4 key购买 nike

所以从我个人的研究来看,闭包/柯里化(Currying)似乎或多或少是完全相同的东西,这不可能是明显正确的。那么区别在哪里呢?

所以这是一个 Racket 中的闭包示例:

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

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


(add3 5)

会回馈

8

那么柯里化(Currying)的区别在哪里呢?因为如果我查找文档和其他示例,它们似乎与我为闭包展示的完全相同?

先谢谢大家了!

最佳答案

所以它们是不同的概念,但都与嵌套的 lambda 相关。

闭包可以由引用在自身外部定义的变量的 lambda 创建,并且当 lambda 从定义外部变量的上下文中转义时最为重要。闭包的工作是确保在 lambda 转义上下文时保留变量。

Curried 函数是一种可以在多个步骤或多个不同的函数应用程序中获取其参数的函数。这通常意味着 lambda 嵌套在 lambda 中。

柯里化(Currying)函数并不总是闭包,尽管它们经常是

大多数有用的柯里化(Currying)函数都需要使用闭包,但如果内部 lambda 忽略外部参数,它们就不是闭包。一个简单的例子:

(define (curried-ignore-first ignored)
(lambda (y) y))

这不是闭包,因为内部 lambda (lambda (y) y) 已经关闭:它不引用自身以外的任何变量。

柯里化(Currying)函数并不总是需要忽略外部参数...它只需要在返回内部 lambda 之前处理它们,这样内部 lambda 就不会引用外部参数。一个简单的例子是柯里化(Currying)的 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)))

闭包并不总是来自柯里化(Currying)函数

当内部 lambda 引用外部上下文中的变量并可能转义该上下文时,需要闭包。外部上下文通常是函数或 lambda,但不一定是。它可以是一个让:

(define closure-with-let
(let ([outer "outer"])
(lambda (ignored) outer))) ; closure because it refers to `outer`

这是一个闭包,但不是柯里化(Currying)的例子。

将 Curried-function-producing-a-closure 变成一个没有闭包的函数

原题中的例子是产生闭包的柯里化(Currying)函数

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

如果你想制作一个仍然是具有相同行为的柯里化(Currying)函数的版本,但在某些特殊情况下不需要对 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 并且不需要再关闭它。

关于functional-programming - Racket - Closure/Currying,区别在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62499789/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com