修改使用 quasiquote 创建的列表是否合法?

Is it legal to modify a list created using quasiquote?

据我了解,修改使用 quote:

创建的列表是不合法的
(let ((numbers '(3 2 1)))
  (set-car! numbers 99)  ; Illegal.
  numbers)

使用 quasiquote 创建的列表呢?修改使用 quasiquote 创建的列表是否合法?

(let ((numbers `(3 2 1)))
  (set-car! numbers 99)  ; Legal?
  numbers)

(let ((numbers `(,(+ 1 2) 2 1)))
  (set-car! numbers 99)  ; Legal?
  numbers)

简短的回答是否定的,这不是“合法的”,当然这绝不应该在旨在可移植的程序中完成。 R6RS 和 R7RS 对此有几乎相同的语言,所以我只引用 R6RS, Section 11.17 Quasiquotation:

A quasiquote expression may return either fresh, mutable objects or literal structure for any structure that is constructed at run time during the evaluation of the expression. Portions that do not need to be rebuilt are always literal.

R7RS 的第 4.2.8 节具有相同的语言,只是它说的是“newly allocated”而不是“fresh”。

既然试图修改 Scheme 中的文字是错误的,那么修改 quasiquote 形式的结果也是错误的。这是你有时似乎可以逃脱的事情,但它迟早会咬你一口。这里真正的问题是“不需要重建的部分总是文字”。其他部分可能是也可能不是文字。

更具体地说,对于 OP 发布的代码,`(3 2 1) 保证 通过 R6RS 第 11.17 节中描述的 quasiquote 的语义来评估列表文字:

Semantics: If no unquote or unquote-splicing forms appear within the <qq template>, the result of evaluating (quasiquote <qq template>) is equivalent to the result of evaluating (quote <qq template>).

R7RS 在第 4.2.8 节中包含类似的语言。由于 (quote (3 2 1)) 创建一个列表文字,表达式 `(3 2 1) 也必须计算为列表文字。

另一方面,OP 代码 `(,(+ 1 2) 2 1) 必须计算 (+ 1 2) 并将结果插入结果结构。在这种情况下,unquote 通过 , 运算符使用,因此生成的列表结构 可能是也可能不是 列表文字。

再举一个例子,考虑准引用表达式 `(,(+ 1 2) (2 1))。这里的主要结果是一个列表结构,它可能是也可能不是列表文字,但是结果结构的元素 (2 1) 保证 是列表文字,因为它确实不需要重建在最后的构建结果。