Scheme 方案分配
当我每次得到值10时计算下面的表达式时Scheme 方案分配,scheme,Scheme,当我每次得到值10时计算下面的表达式时 (((lambda (x) (lambda () (set! x (+ x 10)) x)) 0)) 但是,我只是通过使用名称抽象上述过程来进行修改,并在每次值增加10%时调用foo (define foo ((lambda (x) (lambda () (set! x (+ x 10)) x)) 0)) 有人能解释一下吗?您正在调用的函数是一个计数器,每次调用时都返回一个高10的数字 在第一种情况下,每次都创建一个新函数,然后立即调用它一次,然后丢
(((lambda (x) (lambda () (set! x (+ x 10)) x)) 0))
但是,我只是通过使用名称抽象上述过程来进行修改,并在每次值增加10%时调用foo
(define foo ((lambda (x) (lambda () (set! x (+ x 10)) x)) 0))
有人能解释一下吗?您正在调用的函数是一个计数器,每次调用时都返回一个高10的数字 在第一种情况下,每次都创建一个新函数,然后立即调用它一次,然后丢弃该函数。因此,每次您都是第一次调用此计数器的新实例,因此它应该返回10
在第二种情况下,只需创建一次函数并将其分配给变量,然后重复调用同一函数。因为你调用的是同一个函数,它应该返回10,20,…newacct是正确的,但是我想更详细地讲一下,因为这是我最近才想到的 我将非常松散地使用“环境”和“范围”这两个术语,它们的含义基本相同。记住,这个计划是一个好主意 当scheme计算表达式时,它将在其当前环境中查找表达式中任何变量的值。如果在当前环境中找不到,它将在父环境中查找。如果该值不在父环境中,则它将查找下一个级别,依此类推,直到它到达顶部(全局)级别,在那里它将找到该值或抛出“unbound variable”错误 无论何时调用
define
,都会将符号与该符号表上的值相关联。因此,如果在顶层调用define
,将向全局符号表中添加一个条目。如果在过程主体中调用define
,则会将一个条目添加到该过程的符号表中
(define foo <--- associated name on the symbol table
(lambda (x) <--- scope where x is defined
(lambda () \
(set! x (+ x 10)) |--- body
x)) /
0) <--- initial value of x
考虑对过程调用define
的一个好方法是在符号表中创建一个条目,该条目由该过程的参数、主体和环境组成。例如,过程square
将有一个类似以下内容的条目:
(define a 3)
(define (square x)
(* x x))
GLOBAL
=================
a-|-3
|
square-|-{x}
| {(* x x)}
| {GLOBAL} ---> All the things defined on the global table
(define foo <--- associated name
(let ((x 0)) <--- scope where x is defined & initial x value
(lambda () \
(set! x (+ x 10)) |--- body
x))) /
然后,如果我调用(square a)
解释器将首先查看定义square
的环境,它将发现a
与值3关联。然后x->3在方块体中,程序返回9。酷,有道理
当我们开始在过程中定义helper过程时,事情会变得更加复杂,但您真正需要记住的是,如果在当前环境中找不到任何与符号相关的内容,它将向上移动范围级别,直到找到为止。而且,它总是在第一场“比赛”时停止。因此,如果存在一个本地x
,它将更喜欢它而不是全局x
(相反,它将使用本地x
,而从不寻找全局)
接下来,请记住define
只是将名称添加到符号表中,但是set
是一个实际更改与符号关联的值的变量
所以(define b“blah”)
在符号表中放入一个条目<代码>b=>“废话”。没什么疯狂的<代码>设置代码>将更改实际值:
(set! b "foo")
b => "foo"
但是set代码>无法向表中添加任何内容<代码>(设置!c“bar”)=>未绑定变量c
这是最重要的区别:设置
的行为与任何其他过程类似,如果在当前范围内找不到变量,它将逐步检查更高的级别,直到找到匹配项(或抛出错误),但define
始终向调用它的范围添加绑定
好了,那么您就明白了define
和set之间的区别了代码>。好。现在进入问题
正如newacct指出的那样,表达式((lambda(x)(lambda()(set!x(+x 10))x))0每次都将返回相同的值,因为您每次都在调用一个新过程。但是,如果命名它,则可以跟踪通过调用过程创建的环境
(define foo <--- associated name on the symbol table
(lambda (x) <--- scope where x is defined
(lambda () \
(set! x (+ x 10)) |--- body
x)) /
0) <--- initial value of x