为什么 "eq?" 在以下上下文中评估为 false 而在其他情况下评估为 true?
Why does "eq?" evaluate to false in the following context but true otherwise?
我目前正在练习球拍语言,我运行遇到了一个有趣的问题。我正在尝试比较两个列表的元素。通常,如果我比较两个符号,我会得到以下结果:
> (eq? 'leet 'leet)
#t
> (eq? 'let 'notleet)
#f
出于某种原因,当比较两个列表的第一个元素时,即使它们相等,我也会得到 false。
> (eq? (first '('leet 'a 'f)) (first '('leet 'coder 'a 'f 'f)))
#f
当我基本上比较相同的两件事时,为什么会评估为 false?
when I'm basically comparing the same two things
你不是。 (first '('leet 'a 'f))
是 '(quote leet)
,而不是 ‘leet
。所以你比较的是列表,而不是符号。
'(...)
已经引用了列表的内容。如果您在列表中放置额外的 '
s,它们将被引用。由于 'foo
是 (quote foo)
的快捷方式,引用它可以得到包含这些符号的列表。
如果你只写 '(leet a f)
而没有内引号,它会按你预期的那样工作。
表达式'expression
是(quote expression)
的缩写。计算表达式时,它的计算结果为 expression
作为数据结构或原子值。重要的是要知道 expression
中的任何内容都不会得到进一步评估。因此 ''x
,即 (quote (quote x))
成为列表 (quote x)
。
eq?
用于比较同一个对象。这意味着:
(eq? (list 'leet) (list 'leet)) ; ==> #f
现在两个参数看起来都像 (leet)
,但是这两个列表位于计算机的不同内存位置,因此不相同。
像 "string"
和 '(some list)
这样的常量可能会被创建一次然后被多次引用,但在不同的实现中可能会为代码中的每个位置新创建常量。因此:
(eq? "test" "test") ; ==> #t or #f
(eq? '(leet) '(leet)) ; ==> #t or #f
在你的代码中你有多余的 '
所以 (first '('leet 'a 'f))
实际上是数据 (quote leet)
,一个有两个符号的列表。因此,您正在应用与上面最后一个表达式完全相同的内容,并且您可以期望某些实现中的 #f
和其他一些实现中的 #t
。比较列表与比较符号不同。
因此您可以通过删除多余的 '
来解决此问题。那么我假设您没有尝试列出列表 (quote leet)
。
(eq? (first '(leet a f)) (first '(leet coder a f f)))
; ==> #t
如果你想比较列表,你应该使用 equal?
:
(equal? (first '('leet 'a 'f)) (first '('leet 'coder 'a 'f 'f)))
; ==> #t
并且知道 #lang racket
中的 (first '('leet 'a 'f))
REPL 用两个 '
打印 ''leet
。第一个 '
是球拍有趣的打印值的方式,它计算出它应该打印的值,也许是这种混淆的根源,第二个是你有一个列表 (quote leet)
的指示符,但是许多方案将其缩写为 'leet
.
Sylwester 的回答是正确和详细的,但我想提出 TL/DR;这里:
不要使用 eq?
。相反,使用 equal?
.
这就是故事的全部吗?不,当然不。但是,如果您正在寻找可以牢记在心的单行本,那应该是这个; equal?
几乎总能如愿以偿,而 eq?
通常不会。
我目前正在练习球拍语言,我运行遇到了一个有趣的问题。我正在尝试比较两个列表的元素。通常,如果我比较两个符号,我会得到以下结果:
> (eq? 'leet 'leet)
#t
> (eq? 'let 'notleet)
#f
出于某种原因,当比较两个列表的第一个元素时,即使它们相等,我也会得到 false。
> (eq? (first '('leet 'a 'f)) (first '('leet 'coder 'a 'f 'f)))
#f
当我基本上比较相同的两件事时,为什么会评估为 false?
when I'm basically comparing the same two things
你不是。 (first '('leet 'a 'f))
是 '(quote leet)
,而不是 ‘leet
。所以你比较的是列表,而不是符号。
'(...)
已经引用了列表的内容。如果您在列表中放置额外的 '
s,它们将被引用。由于 'foo
是 (quote foo)
的快捷方式,引用它可以得到包含这些符号的列表。
如果你只写 '(leet a f)
而没有内引号,它会按你预期的那样工作。
表达式'expression
是(quote expression)
的缩写。计算表达式时,它的计算结果为 expression
作为数据结构或原子值。重要的是要知道 expression
中的任何内容都不会得到进一步评估。因此 ''x
,即 (quote (quote x))
成为列表 (quote x)
。
eq?
用于比较同一个对象。这意味着:
(eq? (list 'leet) (list 'leet)) ; ==> #f
现在两个参数看起来都像 (leet)
,但是这两个列表位于计算机的不同内存位置,因此不相同。
像 "string"
和 '(some list)
这样的常量可能会被创建一次然后被多次引用,但在不同的实现中可能会为代码中的每个位置新创建常量。因此:
(eq? "test" "test") ; ==> #t or #f
(eq? '(leet) '(leet)) ; ==> #t or #f
在你的代码中你有多余的 '
所以 (first '('leet 'a 'f))
实际上是数据 (quote leet)
,一个有两个符号的列表。因此,您正在应用与上面最后一个表达式完全相同的内容,并且您可以期望某些实现中的 #f
和其他一些实现中的 #t
。比较列表与比较符号不同。
因此您可以通过删除多余的 '
来解决此问题。那么我假设您没有尝试列出列表 (quote leet)
。
(eq? (first '(leet a f)) (first '(leet coder a f f)))
; ==> #t
如果你想比较列表,你应该使用 equal?
:
(equal? (first '('leet 'a 'f)) (first '('leet 'coder 'a 'f 'f)))
; ==> #t
并且知道 #lang racket
中的 (first '('leet 'a 'f))
REPL 用两个 '
打印 ''leet
。第一个 '
是球拍有趣的打印值的方式,它计算出它应该打印的值,也许是这种混淆的根源,第二个是你有一个列表 (quote leet)
的指示符,但是许多方案将其缩写为 'leet
.
Sylwester 的回答是正确和详细的,但我想提出 TL/DR;这里:
不要使用 eq?
。相反,使用 equal?
.
这就是故事的全部吗?不,当然不。但是,如果您正在寻找可以牢记在心的单行本,那应该是这个; equal?
几乎总能如愿以偿,而 eq?
通常不会。