在 Racket(和其他函数式编程语言)中,lambda
非常有用,当你想要将一个内联、一次性的函数作为参数传递而不必事先定义它时。例如,假设我们想要将一个数字列表平方。我们可以走捷径,首先定义一个 square
函数,然后使用 map
:
(define (square x)
(* x x))
(map square '(1 2 3 4 5))
=> '(1 4 9 16 25)
...或者我们可以像这样简单地传递一个lambda
:
(map (lambda (x) (* x x))
'(1 2 3 4 5))
=> '(1 4 9 16 25)
正如您所看到的,存在一些情况我们不需要引用函数的名称。当然,如果由lambda
表示的过程将在多个部分中被重复使用,或者它是递归的,则给它一个名称是有意义的(这样它就不再是匿名的):
(define square
(lambda (x) (* x x)))
以上等同于开头第一种定义square
的方式。事实上,第一种定义只是为了定义一个函数而已,但最终所有的函数都是lambda表达式!
现在让我们看一下你的示例。这里我们使用的是lambda
的略微不同的用法,并且也举例说明了它们为什么有用——我们不仅定义了一个函数,还返回了一个函数:
(define test
(lambda (x)
(lambda (y)
(+ x y))))
如果我们这样写可能会更加清晰(由于上述原因,它是等效的):
(define (test x)
(lambda (y)
(+ x y)))
甚至更简短 - 在Racket中,我们也可以使用这种语法来实现相同的目的:
(define ((test x) y)
(+ x y))
并不是说这是一种更好的(或者更差的)定义函数的方式 - 这是一种不同的方法!我们正在定义一个名为test
的过程,它接收参数x
并返回一个新的匿名函数作为结果,该匿名函数反过来将接收参数y
。现在,在这些行中:
(define add27
(test 27))
我们使用一个 x
值为 27
调用了 test
函数,该函数返回一个匿名函数,我们将其命名为 add27
。还记得作为参数接收的 y
的 lambda
吗?现在这个 lambda
已经被命名为 add27
,这是柯里化的一个例子。想一想:test
是用于生成将固定值 x
加到给定参数 y
的函数,这就解释了为什么它可以工作:
(add27 2)
=> 29
另一方面,这个函数将始终向其参数添加27
,没有办法更改它:
(define (addTest x)
(+ x 27))
(addTest 2)
=> 29
你看到区别了吗?test
可以让我们生成新的函数,添加任意值,而addTest
始终添加一个固定值27
。如果你想添加例如100
,使用test
就很简单:
(define add100 (test 100))
但是addTest
不能被改变,我们需要编写一个新的函数:
(define (addTest100 x)
(+ x 100))
我希望这能澄清事情,如有其他关于我的回答的问题,请在评论中随意提问。
(define (f) 1)
时,它将返回1
。而且,由于lambda
也是像其他任何值一样的值,如果我们写成(define (f) (lambda (x) x))
,那么我们就有了一个函数,当被调用时,将返回一个匿名函数作为结果。 - Óscar López