有人可以在计划/球拍中向我解释平等吗?

时间:2016-02-26 19:09:07

标签: scheme racket equality quote

所以我今天偶然发现了这件事,让我感到困惑。

(define (x) '(1))
(eq? (x) (x))             ;=> #t
(eq? '(1) '(1))           ;=> #f


(define (y) (list 1))
(eq? (y) (y))             ;=> #f
(eq? (list 1) (list 1))   ;=> #f

有人能解释一下这里发生了什么吗?

3 个答案:

答案 0 :(得分:4)

编译此程序时

(define (x) '(1))
(eq? (x) (x))             
(eq? '(1) '(1)) 

编译成(类似):

(define datum1 '(1))
(define datum2 '(1))
(define datum3 '(1))
(define (x) datum1)
(eq? (x) (x))             
(eq? datum2 datum3) 

因此(x)将始终返回datum1中存储的对象。 另一方面,表达式(eq? '(1) '(1))将是 发现datum2datum3不存储相同的对象。

注意:编译器编写器有一个选择。许多Scheme实现将上述程序编译为:

(define datum1 '(1))
(define (x) datum1)
(eq? (x) (x))             
(eq? datum1 datum1) 

然后在两种情况下结果都是正确的。

注意:quote的文档没有明确说明程序中多次出现的'(1)是否会产生相同的值。因此,此行为可能在将来发生变化。 [虽然我认为目前的行为是一个慎重的选择]

答案 1 :(得分:3)

eq?检查对象是否相同(想想"如果指针指向内存中的相同地址")。

在第一种情况下,您正在使用在编译时创建的文字。比较(和修改)文字通常是未定义的行为。这里看起来过程$('#c').on("mousedown click", function(){ cNote.currentTime = 0; cNote.play(); }); 每次返回相同的文字,但在第二个表达式中,它看起来像2个文字不一样。正如我所说,未定义的行为。

在第二种情况下,您不使用文字但x在执行时创建新列表。因此,每次调用listy都会创建一个新的列表。

答案 2 :(得分:2)

uselpa的答案是正确的。我想扩展引用的数据,但是要进一步扩展。

如您所知,所有Scheme程序都在内部作为语法树读入。特别是在Racket中,您使用read-syntax过程来执行此操作:

> (define stx (with-input-from-string "(foo bar)" read-syntax))
> stx
#<syntax::1 (foo bar)>

您可以使用syntax->datum将语法树转换为基准:

> (syntax->datum stx)
'(foo bar)

quote是一种特殊形式,它的作用是将语法树的引用部分作为基准返回。这就是为什么,对于许多Scheme实现,您的x过程每次都返回相同的对象:它返回语法树的相同部分作为基准。 (这是一个实现细节,并且Scheme实现不需要具有此行为,但它有助于解释您看到所见内容的原因。)

正如uselpa的回答所说,如果列表非空,list每次都会创建一个新列表。这就是为什么与list相比,eq?的两个单独的非空调用结果总是不同的原因。

(在Scheme中,空列表需要表示为单个对象。所以(eq? '() '())保证为真,(eq? (list) '())(eq? (cdr (list 'foo)) (list))等也是如此。 / p>

我不会使用短语&#34;未定义的行为&#34; 比较文字,因为它很容易与UB的C和C ++含义混淆,后者是nasal demons,虽然比较文字的结果可能不是你所期望的,但它不会导致程序崩溃,等等。修改文字当然是鼻子恶魔。