方案中的lambda函数和内存

时间:2013-07-22 14:59:03

标签: scheme lisp racket lambda

我不明白为什么写作

(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部分与函数lambda()相关联使得它保留了我们在之前应用函数时所做的事情的记忆?

3 个答案:

答案 0 :(得分:5)

这就是发生的事情。首先,当你写这篇文章时,你必须明白:

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

它被转换为这种等效形式:

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

所以你看,首先是另一个lambda。现在,最外层 lambda将定义一个局部变量cur,它将“记住”列表的值,然后将返回最里面的结果是lambda,最里面的lambda“捕获”,“包围”closure内部定义的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

答案 1 :(得分:1)

当你将if包装在lambda中(并将其返回)时,cur let(在if的范围内)附加到lambda。这被称为闭包。

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

答案 2 :(得分:1)

请注意,在原始代码中,您将lst重命名为cur。你实际上并不需要这样做。内部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)))