在Scheme中对嵌套的let和lambda进行排序

时间:2011-04-02 12:08:08

标签: lambda scheme

Scheme中两个函数之间有什么区别,一个像这样定义 -

(define doSomething
    (lambda (x)
          (let (f (100))
               (f x))))

和另一个这样? -

(define doSomething
          (let (f (100))
            (lambda (x) 
               (f x)))) 

换句话说,如果lambdalet之前或之后,那么重要的是什么?

3 个答案:

答案 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!的情况下,两者之间没有区别,因此可能没有理由使用你的第二个形成。