Lisp中修改quasiquote创建的列表操作是否合法?
关于准引用(quasiquote)创建列表的可修改性说明
根据R5RS/R6RS Scheme标准规范,修改字面常量的行为属于未定义行为,普通
quote(单引号)创建的列表属于字面常量,因此修改是非法的,示例代码如下:
(let ((numbers '(3 2 1))) (set-car! numbers 99) ; 非法,属于未定义行为 numbers)
准引用创建的列表可修改性分两种情况
准引用的可修改性没有统一答案,取决于表达式是否包含插值逻辑以及你使用的Lisp/Scheme实现:
- 无任何逗号插值的准引用表达式,和
quote语义完全等价`(3 2 1)和'(3 2 1)在标准层面语义完全一致,返回的都是字面常量,大部分实现会将这类对象放到只读存储区,此时执行set-car!修改属于未定义行为,不合法:
(let ((numbers `(3 2 1))) (set-car! numbers 99) ; 未定义行为,不建议使用 numbers)
- 包含逗号插值的准引用表达式,会返回运行时新构造的可变列表
如果准引用中存在,expr形式的插值逻辑,运行时会先计算所有插值表达式的值,再动态构造新的列表对象,这类动态生成的列表是堆上的可变对象,可以合法执行修改操作:
(let ((numbers `(,(+ 1 2) 2 1))) (set-car! numbers 99) ; 合法,运行后返回 (99 2 1) numbers)
最佳实践
如果希望完全规避不同实现的差异,确保你使用的是可修改的列表,不管是否用到插值逻辑,都优先用list函数显式构造列表:(list 3 2 1)返回的一定是可变列表,不存在兼容性问题。
内容的提问来源于stack exchange,提问作者Flux
相关产品推荐
相关产品推荐

