计划中的 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】:

letlambda

例如

(let ((x 1))
  body)

可以翻译成

((lambda (x) body) 1)

此外,在Scheme中所有控制和环境结构都可以用lambda表达式和lambdas的应用来表示。

所以,lambda 严格来说比let 更强大,并且构成了 Scheme 中许多有趣的构造的基础。

关于definelambda,***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 有啥意义?的主要内容,如果未能解决你的问题,请参考以下文章

有啥方法可以参考 terraform 中的旧计划吗?

java8的lamda有啥意义

编译器说 Lambda 表达式中的变量必须是 final 的,我偏不信 | 原力计划

如何使用事件将 json 输入传递给在无服务器中部署的 Cron 计划 Lambda?

使用 Web.config 计划任务比使用 Windows 计划任务有啥好处

AWS Cloudwatch/Lambda - 计划事件触发太频繁