在Scheme中,“set!”的重点是什么?

时间:2009-02-08 17:36:30

标签: scheme

在方案中使用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
> 

4 个答案:

答案 0 :(得分:38)

虽然defineset!都会在同一范围内重新定义一个值,但当范围不同时,它们会做两件不同的事情。这是一个例子:

(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函数时)时,该范围内定义的任何名称都会掩盖显示在封闭范围内的名称。这意味着当我们在definex d 4foo时,我们确实为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时,使用新值创建新变量,而旧变量仍然存在旧值;它只是被新的隐藏了。在命令行中,您没有看到设置的差异!,但定义将不可用于例如命令式程序中的循环计数器。