计划中的 lambda 有啥意义?
Posted
技术标签:
【中文标题】计划中的 lambda 有啥意义?【英文标题】:What's the point of lambda in scheme?计划中的 lambda 有什么意义? 【发布时间】:2011-02-25 22:47:55 【问题描述】:我正在学习计划。我知道如何同时使用 lambda 和 let 表达式。
但是我很难弄清楚使用 lambda 的意义何在。你不能用 let 做所有你可以用 lambda 做的事情吗?
看一个 lambda 表达式比 let 更好的选择的例子会特别有帮助。
另外一件事——在某些情况下 let 比 lambda 更有用吗?如果是这样的话,这样的例子也很好。
编辑:我也对对比 define 和 lambda 感兴趣,因为它们似乎执行类似的任务。
更新:
感谢大家的帮助。阅读您的答案后,我对 lambda/let/define 做了更多研究,现在理解得更好了。
我遇到了一个很酷的 lambda 用法的极好例子——从过程中返回匿名函数。例如,下面的过程operateTwice
返回一个匿名函数,该函数基于传入过程的参数:
(define operateTwice
(lambda (op1 op2)
(lambda (x y)
(op2 (op1 x y) y))))
((operateTwice * +) 2 3) ;equivalent to: (+ (* 2 3) 3), or in standard notation 2*3+3
输出:
9
【问题讨论】:
【参考方案1】:let
是 lambda
。
例如
(let ((x 1))
body)
可以翻译成
((lambda (x) body) 1)
此外,在Scheme中所有控制和环境结构都可以用lambda表达式和lambdas的应用来表示。
所以,lambda
严格来说比let
更强大,并且构成了 Scheme 中许多有趣的构造的基础。
关于define
和lambda
,***define
添加到***环境的绑定。
当你写作时
(define (f x)
body)
你说的是真的
(define f (lambda (x) body))
嵌套定义被翻译成letrec
,也可以使用 lambdas 重写。
所以,同样,很多 Scheme 构造都可以使用lambda
转换成某种东西,因此你理解lambda
真的很值得。
【讨论】:
嘿,你甚至可以用 lambdas 构造自然数和算术运算。 您应该在 CS 网站上回答 anonymous lambda functions (functional programming)。【参考方案2】:如果您想创建一个函数以将其用作另一个函数的参数(例如map
),您可以使用lambda
,但您实际上并不想命名该函数。
例如,如果您想为列表中的每个数字添加 42,您可以这样做:
(define (add42 x) (+ x 42))
(map add42 (list 1 2 3 4))
但是,如果您不想为只使用一次的函数命名,您可以这样做:
(map (lambda (x) (+ x 42)) (list 1 2 3 4))
【讨论】:
谢谢。你能提供一些关于你为什么选择其中一个的细节吗?你说“如果你不想给函数命名......”。但你为什么不呢? 在scheme和其他函数式程序中,您使用函数的次数太多,以至于您不想通过定义它们来污染您的命名空间,即使您只使用它们一次。此外,非常简单的函数无法承担单独定义它们的开销,并且必须在您需要它们的其他地方查找它们的定义会非常烦人。使用一段时间后会变得明显。没有亲身经历是很难解释的。 当你只在一个场合需要它时,为什么要给它一个名字?您可以只传递一个匿名函数,而不是考虑一些不会使命名空间混乱的名称。 @incresiman: 1. 你需要先想一个名字。如果你使用很多这样的小功能,这可能会变得很烦人。 2. 你定义的函数越多,就越难想到一个未使用的函数名。 3. 如果你定义了很多小函数,那么记住哪个函数做什么也将变得更加困难。 4. 如您在我的示例中所见,带有 lambda 的版本也比带有 define 的版本短一些。【参考方案3】:Let 实际上只是 Lambda 表达式的简写。 以下两个表达式是等价的:
(let ((alpha 7)) (* 5 alpha))
((lambda (alpha) (* 5 alpha)) 7)
Lambda 遵循语言的哲学,即一切都应该看起来像一个数学函数。但在实践中,如果变量太多,让我们更容易弄清楚发生了什么。想象一下在 Lambda 块之后定义了其值的 10 个变量,并且您尝试将每个变量与变量名称进行匹配,让变量的值放在它们的名称旁边,这对程序员来说很方便,但不太符合函数式编程哲学。
Lambda 可用于从高阶函数返回函数,但 let 不能这样做。例如:
(define (plus-list x)
(cond ((number? x)
(lambda (y) (+ (sum-n x) y)))
((list? x)
(lambda (y) (+ (sum-list x) y)))
(else (lambda (x) x))
))
> ((plus-list 3) 4)
10
> ((plus-list '(1 3 5)) 5)
14
> ((plus-list 'a) 5)
5
Lambda 也可用于将函数传递给函数:
>(map (lambda (x) (+ 1 x)) '(-1 2 -3))
(0 3 -2)
【讨论】:
【参考方案4】:lambda 创建新的匿名函数,当然每次使用它们时都会对其进行评估。
let 为值创建临时名称并设置一次以在 let 表单定义的范围内使用。
他们真的是非常不同的野兽。
一些例子:
(λ (x) (* 5 x))
(让 ([x 2]) (* 5 x)) 10 (让 ([f (lambda (x) (* 5 x))]) (f 2)) 10
第一种形式创建一个乘以 5 的函数
第二种形式将 2 赋给 x 并将其乘以 5 得到 10
第三个我们使用 1 的函数(乘以 5)并使用 2 作为参数调用它,结果也是 10
【讨论】:
我认为这是有道理的。但是为什么要使用 lambda 而不是定义呢? 你并不总是需要一个函数的名字,因此你并不总是需要定义。 正确 - 从 sepp2k 的回答中得到。为什么你不想命名一个函数呢? (最好在 sepp2k 的回答下做出回应,以免重复此对话)。谢谢! @incrediman,define
是一种特殊形式,不能作为表达式的一部分,因为它会添加或替换变量名,从而弄乱本地环境。这是不可接受的。名称必须在之前的评估中已经存在。【参考方案5】:
在 Scheme 中,过程(或函数)是第一类对象,如列表、数字或字符串。要创建列表文字,请使用名为 list
的原语:
> (define marks (list 33 40 56))
> marks
> (33 40 56)
就像这样,要创建一个过程,您可以使用lambda
原语(或特殊形式):
> (define add-marks (lambda (m) (apply + m)))
> (add-marks marks)
> 129
由于过程是抽象的主要形式,Scheme 为define
提供了一个快捷方式,以便于绑定新过程:
> (define (add-marks m) (apply + m))
除此之外,过程就像所有其他第一类对象一样。它们可以作为参数传递给其他过程,并且一个过程可以评估以产生(或返回)另一个过程。
【讨论】:
【参考方案6】:你可以这样想... 您创建一个使用另一个函数的函数 但是您想让事情变得更加模块化,所以您所做的就是将第二个函数称为第一个函数的参数,这样您就可以在您觉得需要其他功能时更改第二个函数...... 希望这是有道理的
【讨论】:
以上是关于计划中的 lambda 有啥意义?的主要内容,如果未能解决你的问题,请参考以下文章
编译器说 Lambda 表达式中的变量必须是 final 的,我偏不信 | 原力计划
如何使用事件将 json 输入传递给在无服务器中部署的 Cron 计划 Lambda?