题
实际上,我读的书的乐趣,但它可能会被视为功课。在任何情况下,我感觉不舒服本地状态变量在所有使用的语言......就拿这个代码:
(define flip
(let ((count 0))
(lambda ()
(if (= 0 count)
(begin (set! count 1) count)
(begin (set! count 0) count)))))
为什么在1和0之间的这种代码替换?每到这个函数被调用时计数给出的值为0!一个Python当量将是:
class Flip:
def __init__(self):
pass
def __call__(self):
count = 0
if count == 0:
count = 1
return count
else:
count = 0
return count
此返回相同的事情每一次。我很困惑...
解决方案
我有编写编译器用于功能语言一点经验,所以也许的该函数是如何存储/表示在存储器是为了简短说明。每一个功能大致可看作是一对(E,F)其中,E是一组自由变量的,而F是函数本身的“代码”。当调用函数,它需要的值E和代替那些在F中的变量,并且然后使用这些值执行的代码。
所以,你的例子而言,您所定义的变量“翻转”是你让表达式返回的功能。这个函数是你的拉姆达里面的东西。因为“数”是拉姆达之外定义,它是一个自由变量,所以它的存储功能的环境。然后,每次调用(翻转)时,解释转到代码在lambda,看到它需要查找“计数”的值的环境中,这样做,改变它,并返回。这就是为什么每次调用时,存储在“数”的价值依然存在。
如果你想指望每次调用翻页时间为零,把let表达式的拉姆达里面,所以这是一个绑定变量,而不是自由变量。
其他提示
在拉姆达是一个闭合。这是引用一个自由变量(计数),其中,没有被本地定义或参数中的一个的功能,被绑定到最近的封闭词法环境。
被调用的函数是拉姆达,而不是“翻转”。翻转只是你给该所返回了(让...)表达的拉姆达的名称。
对于Python的,我不知道的语言,但它看起来像数应翻转对象的成员,而不是一个局部变量为呼叫
由于您的翻转功能实际上的返回功能强>(其内部拉姆达定义)
每个调用返回的函数时它修改它的环境。
如果你仔细想想的的让的创建环境(并初始化计数为0),只有一次 - 当lambda函数返回给您
在某种意义上拉姆达为您创建一个功能对象其使用的环境中,其最后一帧中被初始化让的单变量计数。每次调用函数时它修改它的环境。 如果调用的翻转的返回与不同环境中的另一函数对象第二次。 (计数初始化为0)然后可以独立地切换所述两个函子。
如果你想它已了解完全是如何工作的,你应该阅读有关的 environmantal模型
它更像
class Flip:
def __init__(self):
self.count = 0
def __call__(self):
if self.count == 0:
self.count = 1
return self.count
else:
self.count = 0
return self.count
<强>更新与更多的解释:强>
在方案的功能是封闭的是“关闭”的周围自由变量count
,这是在它外面的范围限定。该count
是只用功能身体let
定义方式,意味着该功能是可以访问它的唯一的事情 - 做count
有效的一种私人可变状态附加到功能
这是这样的“对象”是在方案传统上创建在SICP - 具有let
定义一组变量(实例变量,初始化为它们的初始值),并且在所述主体限定一组函数,其是已经共享访问实例变量“方法”。这就是为什么它是自然在这里使用一个Python类来表示这是怎么回事,有count
是一个实例变量。
一个更直译成Python 3.x的将是这样的(请注意,这只是近似值,因为Python没有一个let
(有限范围内的局部变量声明)的语法,并且不能使用Python的lambda
s因为不采取语句):
count = 0
def flip():
nonlocal count
if count == 0:
count = 1
return count
else:
count = 0
return count
# pretend count isn't in scope after this
与原始代码的问题是,它具有必要的样式的一个强烈的影响。更惯用解决方案将是:
(define (flip)
(let ((flag #t))
(lambda ()
(set! flag (not flag))
(if flag 1 0))))
要回答这个问题在你对此有何评论ooboo,你想返回功能的功能
(define make-flipper
(lambda ()
(let ((count 0))
(lambda ()
(let ((v count))
(set! count (- 1 count))
v)))))
;; test it
(let ((flip-1 (make-flipper)))
(format #t "~s~%" (flip-1))
(format #t "~s~%" (flip-1))
(format #t "~s~%" (flip-1))
(let ((flip-2 (make-flipper)))
(format #t "~s~%" (flip-2))
(format #t "~s~%" (flip-2))
(format #t "~s~%" (flip-2))))
您可以平凡改变设定!线,使之成为一个计数器,而不是一个导板(更有用的)。