Lisp/Scheme:评估嵌套的空列表/缺点:(())

Tho*_*mas 3 lisp scheme common-lisp expression-evaluation empty-list

我正在使用这个Lisp 编译器进行测试

有一件事情我不明白:如果一个空列表()评估自身:

(format t "~:a" ())
;; => ()
Run Code Online (Sandbox Code Playgroud)

为什么评估几个嵌套的空列表()不会评估为空列表?

(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 () ?
Run Code Online (Sandbox Code Playgroud)

从我的角度来看,()NIL是相同的,所以内部空列表应该首先评估自身,然后外部列表应该“调用”新的内部评估空列表

我的头脑,我认为在进行计算时应该发生这样的情况:(粗体+斜体=当前评估的内容)

(()) => ( () ) => ( () ) => ()

似乎计划也不允许嵌套空列表调用

感谢您的阅读

ign*_*ens 9

在 Common Lisp 及其祖先中,空列表()是通过特殊分配进行自我评估的:它是唯一具有此属性的列表。它也是唯一一个也是符号的列表,在本例中是符号nil(实际上是符号NIL)。人们很容易认为,在实现的内部某个地方,只是说了相当于 的内容(defconstant nil ()),但它比这更神奇:

> (eq () 'nil)
t

> (symbolp ())
t

> (symbol-name ())
"NIL"
Run Code Online (Sandbox Code Playgroud)

这不仅仅是符号的价值nil,它本身就是符号nil()CL真的很神奇。比在Scheme中更神奇,比如说:在Scheme中它仍然是神奇的,只是不那么神奇了。在Scheme中,()是唯一一个不是一对(缺点)的列表,但它也不是一个符号,并且它不是自我评估的。

所以,好吧,这解释了为什么要()对自身求值:它这样做是因为它很神奇。

所以现在考虑尝试评估这种形式:

(())
Run Code Online (Sandbox Code Playgroud)

好吧,首先这不是空列表:它是一个只有一个元素的列表,即空列表。从评价的角度来看它是一种复合形式。好吧,由于空列表(该列表的第一个元素)也是我们 nil可以将这个复合形式重写为

(nil)
Run Code Online (Sandbox Code Playgroud)

这是同一件事(equal '(nil) '(()))是真的。

好的,现在评估者如何处理复合形式?它查看它们的第一个元素并决定要做什么(请参阅此处.

  • 如果它是一个符号,那么该符号应命名为以下之一

    • 特殊操作员
    • 或(可能是本地)函数
    • 或(可能是本地的)宏

    并将进行相应处理。

  • 如果它不是一个符号,它可能是一个列表开头(lambda ...),它被转换成一个匿名函数并被调用。

  • 没有更多的病例了。

那么,哪个是(()),或者等效的(nil)?它是一种复合形式,它的第一个元素是符号nil。所以

  • 有没有nil指定一个特殊的操作员?不——(special-operator-p 'nil)是假的;
  • nil命名宏吗?不——(macro-function 'nil)是假的;
  • nil命名一个函数吗?不 -(fboundp 'nil)是假的。

因此评估者无法处理此表单:它不合法。


请注意,在Scheme中,同样的事情也是不合法的,但原因略有不同:对于Scheme,空列表不是自我评估的,因此评估器看到(())并说(这次忽略宏)这是一个过程调用,其中过程将是评估 的结果(),但这是一个错误。如果我说(define nil '())then(nil)仍然是一个错误:它将评估nil并获取(),但()不是一个过程。


CL 的一个令人惊讶的事情是它(())可以被赋予(本地)含义。令人惊讶的是,这符合 CL:

(flet ((() () ()))
  (()))
Run Code Online (Sandbox Code Playgroud)

CL它是一致的,因为如果符号没有全局函数定义,则允许在本地为符号建立函数定义:

如果包的外部符号COMMON-LISP未定义为标准化函数、宏或特殊运算符,则允许将其词法绑定为函数(例如, with flet),以声明ftype该绑定的 ,并且(在提供这样做的能力)来追踪该绑定。——CLHS

然后是没有全局函数定义的()符号。nil

  • 我真的很喜欢这样一句话:“(()) 可以被赋予(本地)含义。” 我的第一个想法是“但是你在 CL 中绑定了一个符号......”然后你提供了确切的参考资料,上面写着“如果它还没有(某些类型的)绑定,你可以这样做”。这种对细节的关注非常棒! (2认同)