我正在使用这个 Lisp 编译器进行测试
有一件事我不明白: 如果一个空列表
()
评估自身 :
(format t "~:a" ())
;; => ()
为什么评估多个嵌套的空列表
()
不评估为空列表?
(format t "~:a" (()))
;; => EVAL: undefined function NIL
;; why not () ?
(format t "~:a" ((())))
;; => EVAL: (NIL) is not a function name; try using a symbol instead
;; why not () ?
从我的角度来看,
()
和NIL
是相同的,所以内部空列表应该首先评估自身,然后外部列表应该“调用”新的内部评估空列表
我的头脑,我认为在进行计算时应该发生这样的情况: (粗体+斜体=当前评估的内容)
(()) => (()) => (()) => ()
好像Scheme也不允许嵌套空列表调用
感谢您的阅读
在 Common Lisp 及其祖先中,空列表
()
通过特殊分配进行自我评估:它是唯一具有此属性的列表。这也是唯一一个也是符号的列表,在本例中是符号nil
(实际上是NIL
)。人们很容易认为,在实现的内部某个地方,只是说了相当于 (defconstant nil ())
的东西,但它比这更神奇:
> (eq () 'nil)
t
> (symbolp ())
t
> (symbol-name ())
"NIL"
这不仅仅是符号
nil
的值,它就是符号nil
。 ()
在CL中真的很神奇。比在Scheme中更神奇,比如说:在Scheme中它仍然是神奇的,只是不那么神奇了。在Scheme中,()
是唯一不是一对(缺点)的列表,但它也不是一个符号,也不是自评估的。
所以,好吧,这解释了为什么
()
会评估自身:它这样做是因为它很神奇。
所以现在考虑尝试评估这种形式:
(())
好吧,首先这不是空列表:它是一个只有一个元素的列表,这是空列表。从评价的角度来看,它是一个复合形式。好吧,由于空列表(该列表的第一个元素)是 also
nil
,我们可以将这个复合形式重写为
(nil)
这是同一件事:
(equal '(nil) '(()))
是真的。
好的,现在评估者如何处理复合形式?它会查看第一个元素并决定要做什么(请参阅此处。
如果它是一个符号,那么该符号应命名为以下之一:
将会进行相应处理。
如果它不是一个符号,它可能是一个以
(lambda ...)
开头的列表,它被转换为匿名函数并被调用。
没有更多案例了。
那么,哪个是
(())
,或者等效的 (nil)
?它是一种复合形式,它的第一个元素是符号nil
。所以
nil
是否命名了一个特殊的运算符?否 -- (special-operator-p 'nil)
是假的;nil
命名宏吗?否 -- (macro-function 'nil)
是假的;nil
命名一个函数吗?不 - (fboundp 'nil)
是假的。因此评估者无法处理此表格:它不合法。
请注意,在Scheme中,同样的事情也是不合法的,但原因略有不同:对于Scheme,空列表不是自我评估的,因此评估者看到
(())
并说(这次忽略宏)这是过程调用,其中过程将是评估 ()
的结果,但这是一个错误。如果我说 (define nil '())
那么 (nil)
仍然是一个错误:它将评估 nil
并得到 ()
,但 ()
不是一个过程。