我正在为我的计划决赛而学习,与当地国家的对象一直是一个艰难的主题。
这是我期末考试中的一个问题,我需要帮助。
(define (make-incrementer n)
(let ((old 0)
(new 0))
(lambda ()
(cond ((< new n)
(set! old new)
(set! new (+ new 1))
old)
(else
(set! old 0)
(set! new 1)
old)))))
(define a (make-incrementer 3))
(define b (make-incrementer 3))
(define c a)
; 1) (a)
; 2) (a)
为什么第二次调用a
时会返回1?我正在查看代码,我们给它的n
始终为3.所以它不会总是处理else
情况吗?
答案 0 :(得分:3)
欢迎来到封闭的精彩世界!这是关于Scheme中闭包如何工作的教科书示例。
因此make-counter
会返回一个函数,该函数包含3个从其封闭环境中捕获的变量:n
,old
,new
。在这种情况下,起始环境类似于
_name_|_value_
n | 3
old | 0
new | 1
在每次调用时,如果它们大于old
,它会递增new
和n
并将它们包裹起来。因为它正在使用set!
,所以这种递增会改变lambda环境中的变量,但由于这些变量是从周围环境中捕获的,因此它们也会在以后的所有调用中进行更改。
即使使用相同的输入,这也是您获得不同回报的原因。
如果这看起来像巫术,你可以把它想象成更常见语言的对象:
例如Python:
class Foo():
def __init__(self, n, m):
self.n = n
self.m = m
def count(self):
self.n += 1
if self.n == self.m:
self.n = 1
return self.n-1
f = Foo(0, 2)
f.count() # 1
f.count() # 0
这是基本相同的想法,除了这里我们对环境的来源self
更加明确。在Scheme中,我们用lambda捕获周围的变量来模仿它。
有关详情,请查看SICP
答案 1 :(得分:0)
以下是一些示例,可能有助于捕获状态的概念:
(define (always x)
(lambda rest x))
(define always-true (always #t))
(always-true #f)
-> #t
(define (add-n n)
(lambda (m)
(+ n m)))
(define add-1 (add-n 1))
(add-1 10)
-> 11
(define (complement predicate)
(lambda (x)
(not (predicate x)))
(define not-positive? (complement positive?))
(not-positive? -1)
-> #t
接下来是一个示例,其中捕获的状态(在这种情况下为l
)发生了变异。这类似于new
和old
被捕获和修改的情况。
(define (nexting l)
(lambda ()
(if (null? l)
'()
(let ((answer (car l)))
(set! l (cdr l))
answer))))
(define next-user (nexting '(Alice Bob David)))
(next-user)
-> Alice
(next-user)
-> Bob
(next-user)
-> David
(next-user)
'()