在方案中使用set!
赋值运算符有什么意义?为什么不使用rebind
将变量define
变为新值?
> (define x 100)
> (define (value-of-x) x) ;; value-of-x closes over "x"
> x
100
> (value-of-x)
100
> (set! x (+ x 1))
> x
101
> (value-of-x)
101
> (define x (+ x 1))
> x
102
> (value-of-x)
102
>
答案 0 :(得分:38)
虽然define
和set!
都会在同一范围内重新定义一个值,但当范围不同时,它们会做两件不同的事情。这是一个例子:
(define x 3)
(define (foo)
(define x 4)
x)
(define (bar)
(set! x 4)
x)
(foo) ; returns 4
x ; still 3
(bar) ; returns 4
x ; is now 4
正如您所看到的,当我们创建一个新的词法范围(例如我们define
函数时)时,该范围内定义的任何名称都会掩盖显示在封闭范围内的名称。这意味着当我们在define
中x
d 4
到foo
时,我们确实为x
创建了一个隐藏旧值的新值。在bar
中,由于foo
在该范围内不存在,set!
会查找封闭范围以查找和更改x
的值。
另外,正如其他人所说,你只需在范围内define
一次名字。一些实现可以让你逃脱多个define
,有些则不会。此外,您只应对已经set!
d的变量使用define
。同样,强制执行此规则的程度取决于实施。
答案 1 :(得分:5)
通常不允许define
变量不止一次。当你尝试解决问题时,大多数REPL都允许它方便,但如果你试图在Scheme程序中这样做,它会给你一个错误。
例如,在mzscheme中,程序
#lang scheme
(define x 1)
(define x 2)
给出错误
test.ss:3:8: module: duplicate definition for identifier at: x in: (define-values (x) 2)
此外,define
在其他上下文中使用时具有不同的含义。该计划
#lang scheme
(define x 1)
x
(let ()
(define x 2)
x)
x
有输出
1
2
1
这是因为某些构造中的define
实际上被视为letrec
s。
答案 2 :(得分:3)
当你使用词汇绑定时,你不 define
他们:
(let ((x 1))
(set! x (+ x 1))
x)
答案 3 :(得分:2)
使用define时,使用新值创建新变量,而旧变量仍然存在旧值;它只是被新的隐藏了。在命令行中,您没有看到设置的差异!,但定义将不可用于例如命令式程序中的循环计数器。