3

我不明白为什么如果我写

(define (iter-list lst)
  (let ((cur lst))
    (lambda ()
      (if (null? cur)
          '<<end>>
          (let ((v (car cur)))
            (set! cur (cdr cur))
            v)))))

(define il2 (iter-list '(1 2)))

并调用 (il2) 2 次我已打印: 1 然后 2 (这就是我想要的结果)但是如果我不放 (lambda () 并应用 (il2) 2 次我得到然后 1 换句话说,为什么要关联if part to a function lambda() 让它记住我们之前应用该函数时所做的事情?

4

3 回答 3

5

这就是正在发生的事情。首先,重要的是你要明白,当你写这个时:

(define (iter-list lst)
  (let ((cur lst))
    (lambda ()
      ...)))

它被转换成这个等价的形式:

(define iter-list
  (lambda (lst)
    (let ((cur lst))
      (lambda ()
        ...))))

所以你看,另一个lambda首先在那里。现在,最外面 lambda的将定义一个局部变量,cur它将“记住”列表的值,然后将返回最里面的lambda 作为结果,而最里面的lambda“捕获”,cur将上面定义的变量“包围”在一个闭包中。换句话说:iter-list是一个函数,它返回一个函数作为结果,但在这样做之前它会“记住”这个cur值。这就是为什么你这样称呼它:

(define il2 (iter-list '(1 2))) ; iter-list returns a function
(il2)                           ; here we're calling the returned function

将其与此处发生的情况进行比较:

(define (iter-list lst)
  (let ((cur lst))
    ...))

以上等价于:

(define iter-list
  (lambda (lst)
    (let ((cur lst))
      ...)))

在上面,iter-list只是一个函数,它会在调用时返回一个值(不是另一个函数,就像以前一样!),这个函数不会“记住”任何东西,并在被调用后立即返回。总结一下:第一个示例创建一个闭包并记住值,因为它返回一个函数,而第二个示例只返回一个数字,并像这样调用:

(define il2 (iter-list '(1 2))) ; iter-list returns a number
(il2)                           ; this won't work: il2 is just a number!
il2                             ; this works, and returns 1
于 2013-07-22T16:01:14.107 回答
1

请注意,在您的原始代码中,您重命名lstcur. 你实际上不需要这样做。内部的 lambda(要闭包)可以直接捕获lst参数。因此,这将产生相同的结果:

(define (iter-list lst)
  (lambda ()
     ...))   ; your code, replace 'cur' with 'lst'

以下是捕获变量的其他闭包生成函数的一些示例:

(define (always n)
  (lambda () n))

(define (n-adder n)
  (lambda (m) (+ n m)))

(define (count-from n)
  (lambda ()
    (let ((result n))
      (set! n (+ n 1))
      result)))
于 2013-07-22T22:15:25.900 回答
1

当您将 if 包装在 lambda 中(并像那样返回它)时,cur let(在 if 的范围内)将附加到 lambda。这称为闭包。

现在,如果您阅读一些关于闭包的内容,您会发现它们可以用于保持状态(就像您在此处所做的那样)。这对于创建不断递增的计数器或对象系统非常有用(闭包可以用作一种由内而外的对象)。

于 2013-07-22T15:28:39.777 回答