eq ?, eqv?,equal ?,和=在Scheme中有什么区别?
我想知道这些操作之间有什么不同。 我在堆栈溢出中看到了类似的问题,但是它们是关于Lisp的,并且没有三个操作符之间的比较。 所以,如果这已经被问到,请让我知道。
我在Scheme中编写不同types的命令,并得到以下输出:
(eq? 5 5) -->#t (eq? 2.5 2.5) -->#f (equal? 2.5 2.5) --> #t (= 2.5 2.5) --> #t 有人可以解释为什么是这样吗?
 我会逐步回答这个问题。 让我们从=等价谓词开始。  =谓词用于检查两个数字是否相等。 如果你只提供了一个数字,那么它会引发一个错误: 
 (= 2 3) => #f (= 2.5 2.5) => #t (= '() '()) => error 
 这个eq? 谓词用于检查其两个参数是否在内存中表示同一个对象。 例如: 
 (define x '(2 3)) (define y '(2 3)) (eq? xy) => #f (define yx) (eq? xy) => #t 
 但是请注意,内存中只有一个空列表'() (实际上空列表不存在于内存中,但指向内存位置0的指针被视为空列表)。 因此,比较空列表eq? 将始终返回#t (因为它们表示内存中的相同对象): 
 (define x '()) (define y '()) (eq? xy) => #t 
 现在取决于执行情况eq? 可能会或可能不会返回#t ,如数字,string等原始值。例如: 
 (eq? 2 2) => depends upon the implementation (eq? "a" "a") => depends upon the implementation 
 这是eqv? 谓词进入画面。  eqv? 和eq?完全一样eq? 谓词,除了总是返回相同的原始值#t 。 例如: 
 (eqv? 2 2) => #t (eqv? "a" "a") => #t 
 因此eqv? 是eq?的超集eq? 而对于大多数情况下,你应该使用eqv? 而不是eq?  。 
 最后我们来equal? 谓词。  equal? 谓词和eqv?完全一样eqv? 谓词,除了它也可以用来testing两个列表,vector等是否有相应的元素满足eqv? 谓词。 例如: 
 (define x '(2 3)) (define y '(2 3)) (equal? xy) => #t (eqv? xy) => #f 
一般来说:
-  当你想testing两个数字是否相等时,使用=谓词。
-  使用eqv?当你想testing两个非数字值是否相等时谓词。
-  使用equal?当你想testing两个列表,向量等是否相等时,谓词。
-  不要使用eq?谓词,除非你确切地知道你在做什么。
  RNRS规范中有两个页面与eq?, eqv?, equal? and =相关eq?, eqv?, equal? and =  eq?, eqv?, equal? and = 。 这是草案R7RS规范 。 一探究竟! 
说明:
-   =比较数字,2.5和2.5在数字上相等。
-  equal?数字减less到=,2.5和2.5在数字上相等。
-  eq?比较“指针”。 在您的计划实施中,数字5被实现为“立即”(可能),因此5和5是相同的。 数字2.5可能需要在您的Scheme实现中分配一个“浮点logging”,这两个指针并不相同。
 eq? 当它是相同的地址/对象时是#t 。  通常可以期望#t为相同的符号,布尔值和对象,而#f为不同types,不同值或者不同结构的值 。Scheme / Lisp实现有一个embeddedtypes指针和embedded的传统值在同一个空间,如果它有足够的空间。 因此,一些指针实际上不是地址,而是像char R或Fixnum 10那样的值。 这些将是eq? 因为“地址”是一个embedded式的types+值。 一些实现也重用了不可变的常量。  (eq?'(1 2 3)'(1 2 3))在解释时可能是#f,但编译时可能是#t,因为它可能会得到相同的地址。  (就像Java中的常量string池)。 正因为如此,涉及到eq?许多expressioneq? 是未指定的,因此它评估为#t或#f是依赖于实现的。 
 eqv?  与eq?是一样的eq?  。  它也是#t,如果它是一个数字或字符,并且它的值是相同的 ,即使数据太大而不适合指针。 那对于那些eqv? 检查该types的额外工作是否是支持的types之一,它们是相同的types,并且目标对象具有相同的数据值。 
 equal? 是否和eqv? 如果它是一个像pair,vector,string和bytevector这样的复合types,它recursion地equal? 与零件。  在实践中,如果两个对象看起来相同,它将返回#t 。 在R6RS之前,使用equal?是不安全的equal? 在圆形结构上。 
  =就像eqv? 但它只适用于数字types 。 这可能会更有效率。 
 string=? 就像equal?  ,但它只适用于string。 这可能会更有效率。 
 equal? recursion地比较两个对象(任何types)是否相等。 
- 
请注意,对于大型数据结构来说,这可能是很昂贵的,因为必须遍历整个列表,string,向量等。 
- 
如果对象只包含一个元素(EG:数字,字符等),这和 eqv?是一样的eqv?。
 eqv? testing两个对象以确定两者是否“通常被视为同一对象”。 
-  eqv?和eq?是非常相似的操作,它们之间的差异将有一些实现特定的。
 eq? 和eqv? 但可能能够辨别更细微的区别,并且可以更有效地实施。 
-  根据规范,这可能被实现为一个快速和有效的指针比较,而不是一个更复杂的eqv?操作eqv?。
  =比较数字相等的数字。 
-  请注意,可以提供两个以上的数字,例如: (= 1 1.0 1/1 2/2)
 你没有提到一个scheme的实施,但在Racket, eq? 只有当参数引用同一个对象时才返回true。 你的第二个例子是产生#f,因为系统为每个参数创build一个新的浮点数; 他们不是同一个对象。 
 equal? 和=正在检查值相等,但=只适用于数字。 
如果您使用的是Racket,请点击这里查看更多信息。 否则,请检查您的计划实施的文件。
 想想eq? 作为指针平等。  报告的作者希望它尽可能通用,所以他们不要直接这么说,因为它是依赖于实现的,并且说它会偏向基于指针的实现。 但他们确实这样说 
通常可以实现eq? 比eqv更有效率,例如,作为一个简单的指针比较
 这是我的意思。  (eqv? 2 2)保证返回#t但是(eq? 2 2)是未指定的。 现在想象一下基于指针的实现。 在这方面eq? 只是指针比较。 由于(eq? 2 2)被指定,这意味着这个实现可以自由地为它从源代码中读取的每个新数字创build新的内存对象表示。 eqv? 必须真正检查它的论点。 
  OTOH (eq 'a 'a) eq'a'a (eq 'a 'a)是#t 。 这意味着这种实现必须识别具有重复名称的符号,并在内存中为它们全部使用同一个表示对象。 
假设一个实现不是基于指针的。 只要坚持报告,就没有关系。 作者只是不希望被视为执行者的具体实施,所以他们仔细select他们的措辞。
无论如何,这是我的猜测。
 所以非常粗糙, eq? 是指针相等, eqv? 是(primefaces)价值感知, equal? 也是结构感知的(recursion地检查它的参数,所以最后(equal? '(a) '(a))被要求为#t ), =是对于数字, string=? 是用于string的,细节在报告中。