我应该得到一个错误时,修改文字列表?



下面的示例代码出现在R5RS(第26页)和R7RS-small(第41页)中。

(define (g) '(constant-list))
(set-car! (g) 3)  ; Error.

标准指出,当试图修改字面量列表时应该出现错误。然而,当我尝试在MIT Scheme 11.2、Chez Scheme 9.5、Guile Scheme 3.0.1和Racket 7.2 (plt-r5rs)中运行上面的代码时,没有任何错误。是我的理解不正确,还是所有这些方案实现都不符合R5RS和R7RS-small?

底线是你误读了标准,但这是完全可以理解的。

R6RS方案Chez Scheme是R6RS。在R6RS标准第5.10节中说(强调我的):

尝试将新值存储到不可变对象引用的位置应该引发条件类型&断言的异常。

但是在R6RS的第二章中,"should"这个词的意思是"应该"。为本标准的目的而定义:

应该
这个词,或者形容词"推荐的",意思是在特定的情况下,可能有正当的理由可以忽略一个陈述,但在选择不同的课程之前,必须理解和权衡其含义。

这意味着当遇到修改不可变对象的尝试时,实现可以选择是否引发异常。这与Scheme编程语言中所说的一致,该语言由Kent Dybvig (Chez Scheme的创建者)编写,他也是R6RS的编辑之一。文章继续强调,即使在没有引发异常的情况下,修改不可变对象也会导致未指定的行为:

引号和自求值常量是不可变的。也就是说,程序不应该通过set-car!,string-set!等改变常量,并且的实现允许引发异常,条件类型&断言,如果尝试这样的更改。如果未检测到更改不可变对象的尝试,则未指定程序的行为。

在R6RS方案中,在这种情况下不需要引发异常。Chez Scheme是R6RS的实现。

R7RS方案在R7RS标准的3.4节中,围绕不可变对象的讨论,语言做了一些改变(恢复到R5RS语言):

尝试将新值存储到由不可变对象表示的位置是错误的。

但是第1.3.2节讨论了错误报告要求:

当谈到错误情况时,该报告使用短语"错误被标记"表示实现必须检测并报告错误。

set-car!的文档确实显示了这个例子:

(定义(g)"(constant-list))
(set-car !(g) 3)⇒错误

但是没有任何地方说"一个错误被通知"。上面的例子只是说明评估表单的左边会导致错误;在这种情况下,实现不需要检测和发出错误信号。

即使其他实现没有,在这种情况下,Chibi Scheme(它是R7RS的事实上的参考实现)似乎也会引发错误:

> (define (g) '(1 2 3))
> (g)
(1 2 3)
> (set-car! (g) 0)
ERROR on line 3: set-car!: immutable pair: (1 2 3)

R7RS Scheme在本例中与R5RS具有完全相同的语言,set-car!的示例也相同。因此,R7RS和R5RS都不要求实现在试图用set-car!修改列表字面值时引发错误,即使这样做是错误的,并且这样做会导致未指定的行为。

最新更新