Functional programming 在方案中,eq?、eqv?、equal?和=之间有什么区别?

Functional programming 在方案中,eq?、eqv?、equal?和=之间有什么区别?,functional-programming,scheme,equality,equivalence,Functional Programming,Scheme,Equality,Equivalence,我不知道这些计划中的行动有什么区别。我在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 为什么会出现这种情况?您没有提到方案实现,但在Racket中,eq?仅在参数引用同一对象时返回true。第二

我不知道这些计划中的行动有什么区别。我在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

为什么会出现这种情况?

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

equal?
=
正在检查值的等效性,但
=
仅适用于数字


如果你使用球拍,查看更多信息。否则,请查看方案实施的文档。

RnRS规范中有整整两页与
eq?,eqv?,equal?相关?和=
。这是你的电话号码。看看

说明:

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

相等?
递归比较两个对象(任何类型)是否相等

  • 请注意,对于大型数据结构来说,这可能非常昂贵,因为可能需要遍历整个列表、字符串、向量等

  • 如果对象只包含一个元素(例如:数字、字符等),这与
    eqv?
    相同


eqv?
测试两个对象,以确定它们是否“通常被视为同一对象”

  • eqv?
    eq?
    是非常相似的操作,它们之间的差异在某种程度上取决于具体的实现

eq?
eqv?
相同,但可能能够识别出更细微的区别,并且可以更有效地实施

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

=
比较数字是否相等

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

eq?
视为指针相等。本文的作者希望它尽可能通用,所以他们不会直截了当地说这一点,因为它依赖于实现,也就是说,更倾向于基于指针的实现。但是他们说

通常可以实现eq?例如,作为一个简单的指针比较,比eqv?更有效

这就是我的意思
(eqv?2)
保证返回
#t
,但
(eq?2)
未指定。现在想象一个基于指针的实现。在它里面,
eq?
只是指针比较。由于未指定
(eq?2)
,这意味着此实现可以自由地为从源代码读取的每个新数字创建新的内存对象表示形式
eqv?
必须实际检查其参数

OTOH
(等式'a'a)
#t
。这意味着这种实现必须识别具有重复名称的符号,并在内存中为所有符号使用相同的一个表示对象

假设一个实现不是基于指针的。只要它遵守报告,就没关系。作者只是不想被看作是在向实现者口述实现的细节,所以他们仔细选择了自己的措辞

这是我的猜测


因此,非常粗略地说,
eq?
是指针等式,
eqv?
是(原子)值感知,
equal?
也是结构感知的(递归地检查它的参数,所以最后
(equal?)(a)
必须是
\t
=/code>是数字,
字符串=?
是字符串,详细情况见报告

我将逐步回答这个问题。让我们从
=
等价谓词开始。
=
谓词用于检查两个数字是否相等。如果您向其提供除数字以外的任何内容,则会引发错误:

(= 2 3)     => #f
(= 2.5 2.5) => #t
(= '() '()) => error
eq?
谓词用于检查其两个参数是否在内存中代表相同的对象。例如:

(define x '(2 3))
(define y '(2 3))
(eq? x y)         => #f
(define y x)
(eq? x y)         => #t
(eq? 2 2)     => depends upon the implementation
(eq? "a" "a") => depends upon the implementation
(eqv? 2 2)     => #t
(eqv? "a" "a") => depends upon the implementation
(define x '(2 3))
(define y '(2 3))
(equal? x y)      => #t
(eqv? x y)        => #f
但是请注意,内存中只有一个空列表
'()
(实际上,内存中不存在空列表,但指向内存位置
0
的指针被视为空列表)。因此,在比较空列表时,
eq?
将始终返回
#t
(因为它们在内存中表示相同的对象):

现在取决于实现
eq?
可能返回或不返回原始值,如数字、字符串等。例如:

(define x '(2 3))
(define y '(2 3))
(eq? x y)         => #f
(define y x)
(eq? x y)         => #t
(eq? 2 2)     => depends upon the implementation
(eq? "a" "a") => depends upon the implementation
(eqv? 2 2)     => #t
(eqv? "a" "a") => depends upon the implementation
(define x '(2 3))
(define y '(2 3))
(equal? x y)      => #t
(eqv? x y)        => #f
这就是
eqv?
谓词出现的地方。
eqv?
eq?
谓词完全相同,只是对于相同的原语值,它总是返回
#t
。例如:

(define x '(2 3))
(define y '(2 3))
(eq? x y)         => #f
(define y x)
(eq? x y)         => #t
(eq? 2 2)     => depends upon the implementation
(eq? "a" "a") => depends upon the implementation
(eqv? 2 2)     => #t
(eqv? "a" "a") => depends upon the implementation
(define x '(2 3))
(define y '(2 3))
(equal? x y)      => #t
(eqv? x y)        => #f
因此
eqv?
eq?
的超集,在大多数情况下,您应该使用
eqv?
而不是
eq?

最后我们来到
equal?
谓词。
equal?
谓词与
eqv?
谓词完全相同,只是它也可以用来测试两个列表,