Scheme “为什么?”;等式?“;在以下上下文中计算为false,否则为true?

Scheme “为什么?”;等式?“;在以下上下文中计算为false,否则为true?,scheme,racket,evaluation,quote,Scheme,Racket,Evaluation,Quote,我目前正在练习球拍语言,我遇到了一个有趣的问题。我试图比较两个列表的元素。通常,如果我比较两个符号,我会得到以下结果: > (eq? 'leet 'leet) #t > (eq? 'let 'notleet) #f 出于某种原因,当比较两个列表的第一个元素时,即使它们相等,我也会得到false > (eq? (first '('leet 'a 'f)) (first '('leet 'coder 'a 'f 'f))) #f 当我基本上在比较相同的两件事时,为什么这个值是假

我目前正在练习球拍语言,我遇到了一个有趣的问题。我试图比较两个列表的元素。通常,如果我比较两个符号,我会得到以下结果:

> (eq? 'leet 'leet)
#t
> (eq? 'let 'notleet)
#f
出于某种原因,当比较两个列表的第一个元素时,即使它们相等,我也会得到false

> (eq? (first '('leet 'a 'f)) (first '('leet 'coder 'a 'f 'f)))
#f
当我基本上在比较相同的两件事时,为什么这个值是假的

当我基本上比较相同的两件事

你不是<代码>(第一个“('leet'a'f))是
”(引用leet)
,而不是
'leet
。所以你是在比较列表,而不是符号

(…)已经引用了列表的内容。如果您在列表中添加了额外的
s,这些将被引用。由于
'foo
(quote foo)
的快捷方式,因此引用它会给出包含这些符号的列表


如果你只写
”(leetaf)
,而不带内引号,它会像你期望的那样工作。

表达式
'expression
(引号表达式)
的缩写。当对表达式求值时,它将作为数据结构或原子值求值为
expression
。重要的是要知道,
表达式
中的任何内容都不会得到进一步的计算。因此,
“x
,即
(quote(quote x))
成为列表
(quote x)

eq?
用于比较同一对象。这意味着:

(eq? (list 'leet) (list 'leet)) ; ==> #f
现在这两个参数看起来都像
(leet)
,但这两个列表位于计算机中不同的内存位置,因此并不相同

“string”
”(一些列表)
这样的常量可以创建一次,然后引用多次,但是在不同的实现中,可以为代码中的每个位置新创建常量。因此:

(eq? "test" "test")   ; ==> #t or #f
(eq? '(leet) '(leet)) ; ==> #t or #f
在代码中有多余的
,因此
(first'('leet'a'f))
实际上是数据
(quote leet)
,一个带有两个符号的列表。因此,您正在应用与上面最后一个表达式完全相同的表达式,您可以从一些实现中获得
#f
,从其他一些实现中获得
#t
。比较列表与比较符号不同

因此,您可以通过删除额外的
来修复此问题。那么我假设您没有尝试创建列表
(引用leet)

如果要比较列表,应使用
equal?

(equal? (first '('leet 'a 'f)) (first '('leet 'coder 'a 'f 'f)))
; ==> #t

并且知道
(第一个“('leet'a'f))
#lang racket
REPL打印
“leet
和两个
。第一个
是rackets一种有趣的打印值的方式,它的计算结果是它应该打印的值,这可能是这种混淆的根源,第二个是你有一个列表
(引用leet)
,但许多方案将其缩写为
“leet

,Sylvester的答案是正确和详细的,但我想提出TL/DR;在这里:

不要使用
eq?
。相反,请使用
equal?

这就是全部吗?不,当然不是。但是如果你想在你的大脑中找到一条直线,那么应该是这条
equal?
几乎总是做你想做的事,而
eq?
通常不做。

你不是在比较两个符号
'leet
'leet
,而是在比较两个列表,
(列表'quote'leet)
(列表'quote'leet)
。我建议您避免使用
报价
进行列表和阅读。如果您使用
list
,则程序可以运行,如
(第一个(list'leet'a'f))
(第一个(list'leet'coder'a'f')
(equal? (first '('leet 'a 'f)) (first '('leet 'coder 'a 'f 'f)))
; ==> #t