我不明白为什么写作
(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()相关联使得它保留了我们在之前应用函数时所做的事情的记忆?
答案 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)))