R7RS-small准引用表达式等价性:为何同求值结果的list形式不等价
核心差异是对象身份标识和可变性的语义不同
R7RS中此处提到的「等价」指的是语义完全等价,而不仅仅是equal?判断的结构值相等,二者的核心区别如下:
- 前三个表达式里的嵌套列表
(1 2)是静态字面量:
准引号中的字面量结构会被隐式添加quote修饰,最终对应程序代码里的常量对象。这个对象在程序加载时就被分配,多次求值得到的都是同一个eqv?相等的实例,Scheme标准规定尝试修改常量字面量会触发未定义行为。
以第二个等价的cons写法为例,'(1 2)就是典型的常量引用,所有出现'(1 2)的位置默认指向同一个不可变对象。 - 第四个用
list构造的表达式每次求值都会重新分配新对象:list和list的嵌套调用是运行时的动态构造行为,每次执行都会为(1 2)、外层大列表分配全新的pair对,每次求值得到的列表实例都不满足eqv?相等,且是可合法修改的可变对象。
我们可以用下面的测试直观验证差异:
;; 测试前三个表达式的语义,取常量部分 (define (test-quasi) (let ((a 3)) `((1 2) ,a ,4 ,'five 6))) (eqv? (car (test-quasi)) (car (test-quasi))) ;; 绝大多数实现返回 #t,两次取到的(1 2)是同一个对象 ;; 测试list构造的表达式 (define (test-list) (let ((a 3)) (list (list 1 2) a 4 'five 6))) (eqv? (car (test-list)) (car (test-list))) ;; 所有标准实现返回 #f,两次取到的(1 2)是新分配的不同对象
正是因为动态分配带来的对象身份、可变性、副作用表现都和常量准引用表达式不一致,所以即使二者的equal?结果相同,也不被认定为等价。
内容的提问来源于stack exchange,提问作者Flux
相关产品推荐
相关产品推荐

