在Common Lisp中,NULL和NIL有什么确切的区别?

5
据我所理解,NIL 是许多事物的符号:空列表或布尔值 false。这很好理解,但为什么有时输出中会出现 NULL?
clisp> (type-of NIL)
NULL
clisp> (type-of t)
BOOLEAN
clisp> (type-of (not t))
NULL
clisp> NIL
NIL
clisp> (eq NULL NIL)
ERROR..

因此,NULL并非像"BASIC-STRING-6"一样是已定义的符号。但是,我对将NULL用作布尔值时的术语感到有些困惑,因为无论是否否定,布尔值应该始终保持为布尔值。


尝试使用(type-of "elephant")(type-of (not "elephant"))t恰好是布尔值的事实是偶然的。 - Sergey Orshanskiy
5个回答

10

NIL是一个符号,也可以写成()。使用type-of的输出并不一定有用。HyperSpec关于type-of的描述是:

返回一个类型说明符(typespec),该类型含有该对象作为元素。

但是,在考虑类型层次结构以及通用类型(t表示的是所有类型)时,type-of的输出可能没有太大帮助。如果想要知道某个对象是否具有特定的类型,则更有用的是使用typep。使用typep,我们可以看到,无论type-of告诉我们什么,nil都是一个布尔值、一个符号、一个列表和一个空值。另一方面,t是一个符号、一个布尔值,不是一个列表,也不是一个空值。

CL-USER> (type-of nil)
NULL
CL-USER> (type-of t)
BOOLEAN
CL-USER> (typep nil 'boolean)   ; both are booleans
T
CL-USER> (typep t 'boolean)
T
CL-USER> (typep nil 'symbol)    ; both are symbols
T
CL-USER> (typep t 'symbol)
T
CL-USER> (typep nil 'list)      ; only nil is a list
T
CL-USER> (typep t 'list)
NIL
CL-USER> (typep nil 'null)      ; only nil is a null
T
CL-USER> (typep t 'null)
NIL

5
你可能会觉得奇怪,T 是一个布尔值,而 NIL 不是。原因是 NIL 有几个不同的用途。它既可以表示空列表,也可以表示符号 NIL,还可以表示布尔值 false。因此,在某些情况下,它出现在不适合布尔类型的上下文中,从类型安全的角度来看,布尔类型对它来说并不合适。类似地,在 Scheme 中,布尔值 false 和空列表是不同的。

NILtype 是 NULL。

NIL 是代表 NULL 的符号,在 Common Lisp 中使用。它也是表示空列表 () 的方式。#'NULL 是检查变量是否为 NULL(即 eq NIL)的函数。

如果你想使用 NULL 而不是 NIL,你可以定义 NULL。(实际上这可能是一个可怕的想法。

(defconstant null nil)
(type-of NULL) ; ==> NULL
NULL           ; ==> NIL
(eq NULL NIL)  ; ==> T

2
在理解时,对我最有帮助的是认识到NIL实际上只是一个符号,但它是非常特殊的一个。 - math
1
虽然可以定义“null”,但这可能不是一个好主意,因为它会导致非典型的代码,让人措手不及。 - Joshua Taylor
你可能认为 T 是一个布尔值,而 NIL 不是,这听起来很奇怪。但实际上,NIL 也是一个布尔值,因为 (typep nil 'boolean) => T 成立。 - Joshua Taylor
@JoshuaTaylor CL 中的每个对象都是布尔值。当我写这篇文章时,我描述了 OP 在使用 type-of 时所遇到的情况。因此,这是最具体的类型。还要注意 @osa 在我一年前写作后进行了编辑。 - Sylwester
是的和不是... 我明白你的意思,但为了那些发现这个问题的经验不足的读者, 类型 boolean 只包含符号 t 和 nil。但是 所有东西 都是广义布尔值,并且大多数运算符都接受广义布尔值。 - Joshua Taylor

3

确切的区别是NULL是您上下文中的类型,而NIL是一个符号。

NULL是仅包含符号NIL的类型。

NIL作为类型是空类型(没有对象具有类型NIL):

NIL作为对象是表示各种“非”事物的符号。


1

所以NULL不是一个被定义的符号,就像“BASIC-STRING-6”一样。

NULL 一个符号。它没有值。符号NULL是类型NULL和函数NULL的名称。作为类型,NULL有一个元素:NIL

NIL是一个符号,NIL是它的值。因此,NIL是一个常量,其值为自身。NIL也是一个类型,即没有对象的空类型。


-1

像INTEGER,(ARRAY *),(MEMBER T NIL)等类型标识符不会计算出一个值。因此,如果您尝试评估它,NULL类型名称引发错误也就不足为奇了。请记住,类型/子类型层次结构不是简单的树形结构,因此NULL是许多东西的子类型;CONS,BOOLEAN,LIST等。

请注意,许多被视为真实的事物并不属于BOOLEAN类型。BOOLEAN只是'(member nil t)的简写。因此,(type 'foo'(member nil t))等同于'(typep 'foo 'boolean)。

在学习曲线的这个阶段,值得记住的是,Common Lisp是动态类型的,类型声明更倾向于文档和建议,编译器的优化器和警告子系统可以接受或忽略。

NULL也是一个函数。查看手册索引可能会有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接