了解Lisp中的数据模式,为什么这些表达式不一样?

时间:2013-12-01 14:12:36

标签: common-lisp equality land-of-lisp

目前我正在阅读“Lisp之乡”。在最近的一个代码示例中,作者给出了:

> (eq 'fooo 'FoOo)
T

证明符号不区分大小写。几页之后数据模式正式推出。

但是我没有真正了解以下内容。 eq是一个函数,因此它的名称也不区分大小写。因此,我应该能够做到这一点:

> (eq 'Eq 'EQ)
T

大。这按预期工作。但是如果我把它放在数据模式的列表中呢?请记住,我只是在试验一些对我来说很新的东西。

> (eq '(Eq) '(EQ))
NIL
> (eq '('Eq) '('EQ))
NIL

嗯。好的?这是为什么?我原以为如果我将相同的符号放入两个列表中,那么这些列表将被认为是相同的。

现在的问题是:这是否意味着不会比较列表的内容,而是列出“对象”本身?我错过了什么?

4 个答案:

答案 0 :(得分:4)

符号区分大小写

> (eq (print (intern "foo")) (print (intern "FOO")))
|foo|   ; printed 
FOO     ; printed
==> NIL ; returned

默认阅读器为Case-Converting

(eq (read-from-string "foo") (read-from-string "FOO"))
==> T

但是,您可以使读者保留案例:

(let ((*readtable* (copy-readtable)))
  (setf (readtable-case *readtable*) :preserve)
  (eq (read-from-string "foo") (read-from-string "FOO")))
==> NIL

请看一下

EQ比较指针标识

Common Lisp provides 4 equality predicates,你应该根据自己的需要使用正确的:

(equal '(Eq) '(EQ))
==> T
(equal '('Eq) '('EQ))
==> T

答案 1 :(得分:2)

eq比较完全相同的,认为指针相等。这与Java中的==类似,即使逻辑上等效的数据也是假的。

这里的解决方案是使用equal来执行“智能”操作并比较列表元素

> (equal '(A) '(a))
T

此外,符号区分大小写。但默认情况下,阅读器(将代码转换为AST的内容)默认为不区分大小写。您可以通过intern等函数注意到这种区别。

答案 2 :(得分:1)

Lisp符号区分大小写。甚至lisp阅读器也区分大小写。唯一的一点是,当读者读取符号时,通常会将其设为大写。最简单的方法是告诉读者重要的是将它放在垂直线之间。

> '|asd|def|ghj|
|asdDEFght|
> '|asd|
|asd|
> '|ASD|
ASD
> 'ASD
ASD
> (eq 'asd '|ASD|)
t
> (eq 'asd '|aSd|)
nil

eq谓词检查参数是否是相同的对象(类似于比较C中变量的指针)

> (defparameter *x* 1)
> (defparameter *y* 1)
> (eq *x* *y*)
nil

因此,当您在'(asd)中编写REPL时,会创建包含一个元素的列表。当你第二次写它时,会创建另一个列表,这些列表实际上是不同的对象。

> (defparameter *list1* '('qwe))
> (defparameter *list2* '('qwe))
> (eq *list1* list2*) ;this are 2 different objects
nil
> (setf (first *list1* 'def))
> *list1* ;this list has changed
(DEF)
> *list2* ;and this did not
(QWE)

> (setf *list1* *list2*) ;now they are just different names for one object
> *list1*
(QWE)
> (eq *list1* *list2*)
t

还有其他方法可以比较对象(eq eql equal equalp =)。最好阅读文档并使用REPL来查看差异。

答案 3 :(得分:1)

稍微复杂一点。

假设我们在文件中有以下内容。然后我们编译并加载该文件。

(defparameter *a* '(1))
(defparameter *b* '(1))

现在我们计算:

(eq *a* *b*)

如果是NILT,则未定义。 Common Lisp编译器可能检测到列表是equal并将两个变量设置为同一个列表 - 即EQ然后也是如此。实际上有Common Lisp编译器正在这样做。在* REPL DEFPARAMETER中执行两个one would usually expect that the Lisp system does not detect that and that表单(eq a * b *)is NIL`。

EQUAL比较结构,我的示例(eq *a* *b*)总是T