方案中的eq?,eqv ?, equal?和=有什么区别?

yra*_*lik 72 scheme functional-programming

我想知道这些操作之间有什么区别.我在Stack Overflow中看到了类似的问题,但它们是关于Lisp的,并且没有三个运算符之间的比较.所以,如果已经提出这个问题,请告诉我.

我在Scheme中编写不同类型的命令,我得到以下输出:

(eq? 5 5) -->#t
(eq? 2.5 2.5) -->#f
(equal? 2.5 2.5) --> #t
(= 2.5 2.5) --> #t
Run Code Online (Sandbox Code Playgroud)

有人可以解释为什么会这样吗?

Aad*_*hah 135

我会逐渐回答这个问题.让我们从=等价谓词开始.该=谓词用于检查两个数字是否相等.如果您提供除了数字之外的任何其他内容,那么它将引发错误:

(= 2 3)     => #f
(= 2.5 2.5) => #t
(= '() '()) => error
Run Code Online (Sandbox Code Playgroud)

所述eq?谓词用于检查其两个参数是否respresent同一对象在内存中.例如:

(define x '(2 3))
(define y '(2 3))
(eq? x y)         => #f
(define y x)
(eq? x y)         => #t
Run Code Online (Sandbox Code Playgroud)

但请注意'(),内存中只有一个空列表(实际上内存中不存在空列表,但是指向内存位置的指针0被视为空列表).因此,比较空列表时eq?将始终返回#t(因为它们代表内存中的同一对象):

(define x '())
(define y '())
(eq? x y)      => #t
Run Code Online (Sandbox Code Playgroud)

现在,根据实现eq?可能会或可能不会返回#t原始值,如数字,字符串等.例如:

(eq? 2 2)     => depends upon the implementation
(eq? "a" "a") => depends upon the implementation
Run Code Online (Sandbox Code Playgroud)

这是eqv?谓词出现的地方.它eqv?eq?谓词完全相同,只是它总是返回#t相同的原始值.例如:

(eqv? 2 2)     => #t
(eqv? "a" "a") => depends upon the implementation
Run Code Online (Sandbox Code Playgroud)

因此eqv?是一个超集,eq?在大多数情况下你应该使用eqv?而不是eq?.

最后我们来到equal?谓词.的equal?谓词是完全一样的eqv?谓词,不同之处在于它也可以被用来测试是否两个列表,载体等具有满足相应的元件eqv?谓词.例如:

(define x '(2 3))
(define y '(2 3))
(equal? x y)      => #t
(eqv? x y)        => #f
Run Code Online (Sandbox Code Playgroud)

一般来说:

  1. =当您希望测试两个数字是否相等时,请使用谓词.
  2. eqv?当您希望测试两个非数字值是否相等时,请使用谓词.
  3. equal?当您希望测试两个列表,向量等是否相同时,请使用谓词.
  4. eq?除非您确切知道自己在做什么,否则不要使用谓词.

  • AFAIK`(eqv?"a""a")==>未指定`.你必须使用`equal?`或(可能更优化)`string =?` (6认同)
  • 非常准确和信息丰富.特别是最后的指导方针. (4认同)
  • 根据[报告](http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-ZH-9.html#%_idx_216),`(eq?'(1)'(1)) `是*未指定*,所以你的`(define x'(1 2))`插图可能不起作用. (2认同)
  • 一般建议+1. (2认同)
  • 但是 eq? 似乎是为符号定义的,应该注意这一点!如果符号看起来相同,eq? 返回#t。示例 `(eq? 'foo 'foo) -> #t` ,`(eq? 'foo 'bar)` -> false`。我在[这里](http://www.cs.hut.fi/Studies/T-93.210/schemetutorial/node11.html)和[这里](https://courses.cs.washington.edu/courses/ cse341/03wi/scheme/basics.html) (2认同)

GoZ*_*ner 13

RNRS规范中有两页与之相关eq?, eqv?, equal? and =.这是草案R7RS规范.看看这个!

说明:

  • = 比较数字,2.5和2.5在数值上是相等的.
  • equal?对于数字减少到=,2.5和2.5在数值上相等.
  • eq?比较'指针'.在Scheme实现中,数字5实现为"立即"(可能),因此5和5是相同的.数字2.5可能需要在Scheme实现中分配"浮点记录",两个指针不相同.

  • 已更新为实时链接. (2认同)

Syl*_*ter 9

eq?#t什么时候它是相同的地址/对象.通常,人们可以期望#t用于相同的符号,布尔和对象,#f用于不同类型的值,具有不同的值,或者不同的结构 Scheme/Lisp实现具有在其指针中嵌入类型和嵌入的传统如果空间足够,则在同一空间中的值.因此,一些指针实际上不是地址而是值,如char R或Fixnum 10.这些将是eq?因为"地址"是嵌入式+值.一些实现还重用不可变常量.(eq?'(1 2 3)'(1 2 3))在解释时可能是#f但编译时可能是#t,因为它可能得到相同的地址.(与Java中的常量String池一样).因此,涉及的许多表达eq?都是未指定的,因此评估为#t或#f是依赖于实现的.

eqv?是#t用于同样的事情eq?.它也是#t,如果它是一个数字或字符,它的值是相同的,即使数据太大而不适合指针.因此,对于那些eqv?检查该类型的额外工作是受支持的,两者都是相同的类型,并且它的目标对象具有相同的数据值.

equal?是#t用于相同的东西eqv?,如果它是一个复合类型,如pair,vector,string和bytevector,它递归地处理equal?部分.在实践中,如果两个对象看起来相同,它将返回#t.在R6RS之前,equal?在圆形结构上使用是不安全的.

=就像eqv?它仅适用于数字类型.它可能更有效率.

string=?就像equal?,但它只适用于字符串.它可能更有效率.


Jus*_*ier 6

equal? 递归地比较两个对象(任何类型)的相等性.

  • 请注意,对于大型数据结构而言,这可能很昂贵,因为必须遍历整个列表,字符串,向量等.

  • 如果对象只包含一个元素(EG:数字,字符等),则与之相同eqv?.


eqv? 测试两个对象以确定两者是否"通常被视为同一对象".

  • eqv?并且eq?是非常相似的操作,它们之间的差异将在某种程度上与实现有关.

eq?是相同eqv?但可能能够辨别更精细的区别,并且可以更有效地实施.

  • 根据规范,这可以实现为快速有效的指针比较,而不是更复杂的操作eqv?.


= 比较数字相等的数字.

  • 请注意,可以提供两个以上的数字,例如: (= 1 1.0 1/1 2/2)


小智 5

您没有提到方案实现,但是在Racket中,eq?仅当参数引用相同的对象时才返回true。您的第二个示例产生#f,因为系统正在为每个参数创建一个新的浮点数。他们不是同一个对象。

equal?并且=正在检查值是否相等,但=仅适用于数字。

如果您使用的是球拍,请在此处查看更多信息。否则,请检查方案实施的文档。

  • 更好的是...阅读规范... http://www.r6rs.org/final/html/r6rs/r6rs-ZH-14.html#node_sec_11.5 (3认同)