Scheme中两个函数之间有什么区别,一个像这样定义 -
(define doSomething
(lambda (x)
(let (f (100))
(f x))))
和另一个这样? -
(define doSomething
(let (f (100))
(lambda (x)
(f x))))
换句话说,如果lambda
在let
之前或之后,那么重要的是什么?
答案 0 :(得分:5)
您的代码无法运行。 : - )
我认为你的意思是:
(lambda (x)
(let ((f 100))
(+ f x)))
和
(let ((f 100))
(lambda (x)
(+ f x)))
在这两种情况下,你都会收回传入的参数加上100。
然而,主要区别(忽略let
如何只是lambda
的句法糖)的技术问题是,在第二个版本中,f
是一个自由变量。说我们这样做:
(let ((f 100))
(list (lambda (x)
(+ f x))
(lambda (x)
(set! f x))))
这将返回一个包含两个lambdas的列表:第一个与之前的一样,第二个允许您更改f
的值。两个lambda都访问相同的f
,因此运行setter 将影响以后对第一个lambda的调用。
答案 1 :(得分:5)
Chris指出,代码不会运行。所以我将使用一个新示例来解释let
超过lambda
成语。
当您使用lambda
这样的let
表单包围时:
(let ((x 0))
(lambda ()
; body
))
即使在lambda
结束并返回新功能之后,x
正文中的代码也能够访问(包括修改)let
。这是创建“闭包”的一个例子,起初很难理解。
基本上这意味着你可以用一种“内部状态”创建一个函数。您可以使用它来执行诸如制作“累加器生成器”之类的操作,或者创建计算它们被调用次数的函数,甚至模拟“对象”(内部状态+方法)。这是一些人为的例子:
一个double
函数,用于计算调用它的次数:
(define double
(let ((count 0)) ; closed over variable
(lambda (x)
(if (eq? x 'count)
count
(begin
(set! count (+ count 1)) ; incr the count variable introduced by let
(+ x x))))))
> (double 1)
2
> (double 1)
2
> (double 1)
2
> (double 'count) ; ask the double function how many times it's been called
3
>
这个例子非常礼貌Paul Graham(http://www.paulgraham.com/accgen.html)
(define make-accumulator
(lambda ()
(let ((x 0))
(lambda (i)
(set! x (+ x i)) ; incr x by i
x))))
> (define acc (make-accumulator))
> (acc 1)
1
> (acc 1)
2
> (acc 1)
3
> (acc 1)
4
>
每次使用acc
调用1
时,返回的值都不同。
有关“对象”的示例搜索“对象和闭包”或只阅读SICP的相关部分:http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#%_sec_3.1
答案 2 :(得分:2)
其他两个(优秀)海报围绕但未明确提及的一点是:在没有set!
的情况下,两者之间没有区别,因此可能没有理由使用你的第二个形成。