The Racket Reference阅读笔记。

4.1 Equality

等同性在概念上是指判定两个量值是否相等。但这看似容易,实则很难,因为不同类型的量值有不同的等同性要求。为此,Racket提供了三级等同性判定:

  • eq?,判定两个量值是否指向同一个标的。问题是,如果两个量值具有相同的内容,但是分属不同的标的,eq?的判定会失败。失败的例子:
    • (eq? (expt 2 100) (expt 2 100))
    • (eq? (mcons 1 2) (mcons 1 2))
  • eqv?,在eq?的基础上增加了对字符和数值类型的特殊处理,对于内容为字符串和数值的标的,eqv?会检查其内容,并根据内容做出等同性判定,但eqv?的问题是不会对复合结构所包含的子内容进行检查。
  • equal?,在eqv?的基础上,增加了对这些类型的特殊处理:字符串,字节串,子对,可变更子对,串列,封箱,哈希表,以及可检视的结构类型。
    • 即便复合类型的内容包含引用回环,equal?也能正确处理
    • 对于结构类型,可以通过gen:equal+hash以及prop:impersonator-of对其行为进行自定义

4.1.1 Object Identity and Comparisons

eq?适合用在与定性更新(更新的效果在所有地方都可能)的场景中,因为与定性更新产生新的标的对照。

但有些情况下,eq?不适用,因为什么适合该生成新的标的,什么适合不生成新的标的并没有明确的定义,编译器可以根据自己的优化上的需要自行决断。有时候相同的操作,比如(+ 1 2)会返回相同内容的不同标的。另外一个例子,lambda构造的运算有可能生成新的执行决标的,也有可能重用旧标的。

需要查看每种数据类型的说明才能知晓其在eq?的具体表现。

4.1.2 Equality and Hashing

所有的课比较的量值都至少有一个哈希码,用fixnum表示的整型。对其的要求是同样的量值必须有同样的哈希码。但是不同的量值也可能有相同的哈希码。

相关执行决

  • (equal-hash-code v) → fixnum?
    • 能够处理引用回环
    • 可以适用gen:equal+hash自定义
    • 读取过程,对于相同的字符输入,应有相同的输出
    • equal?判定为相同的量值返回的哈希码必须也相同
  • (equal-secondary-hash-code v)
    • 额外的哈希码,用于双重哈希的场景
    • 如果不需要双重哈希,那么可能返回和equal-hash-code相同的值
  • (eq-hash-code v)
    • eq?判定为相同的量值返回的哈希码必须也相同
  • (eqv-hash-code v)

4.1.3 Implementing Equality for Custom Types

  • gen:equal+hash,用于给结构类型自定义哈希功能
    • equal-proc
    • hash-proc
    • hash2-proc
  • prop:equal+hash,废弃不用

(本篇完)