在 Lisp 可以评估某些内容之前,必须先读入。 Read 操作采用一些数据的文本表示并将其转换为 Lisp 数据。
[6]> (read)
'a ; I typed this
'A ; CLISP responded
[7]> (type-of *) ; * is previous-value
CONS
[8]> (mapcar #'print **) ; ** is value before previous value
QUOTE ; first element of the list (code form), (QUOTE A)
A ; second element of the list
'A ; CLISP translates (QUOTE A) back into 'A, for show
所以' ... 在读取时变成了(quote ...)。这是如何工作的?
[4]> (get-macro-character #\')
#<SYSTEM-FUNCTION SYSTEM::QUOTE-READER> ;
NIL
所以there is something there behind the quote。 quote-reader 系统函数。列表也很特别:
[5]> (get-macro-character #\()
#<SYSTEM-FUNCTION SYSTEM::LPAR-READER> ;
NIL
读取所有内容后,然后评估结果。这就是 "read-eval-print loop" 的 "read-eval" 部分,即 REPL。评估a quote form、(quote ...) 的结果是其中的任何内容。 IOW 顶部的quote 消失了,但所有内部的quotes 仍然存在。
没有报价,一切都会被评估。所以要评估(cdr (FEE FI)),必须评估(FEE FI) 的形式,如果它产生一个列表,则该列表的cdr 将被返回。
您可以try to define 表示文字数据的另一种方式,例如用[ ... ] 括号代表(quote ( ... ))。转换可以将 inner 括号视为简单的括号。然后两个
> (cdar [(fee fi) (fo fum)])
> (cdar [[fee fi] [fo fum]])
的行为与您预期的一样。
PS。 CLHS 是你的朋友。
编辑:这就是你犯错的地方。在你的最后一个例子中,
[77]> (car '('(fee fi) '(fo fum)))
'(FEE FI)
[78]> (cdr '(FEE FI))
(FI)
最后一次通话应该是
[1]> (cdr (quote '(FEE FI)))
((FEE FI))
将'(FEE FI) 放入quote 表单中会阻止其评估,因此将其按原样传递给cdr。以下是我们可以确定的方法:
[2]> (car '('(fee fi) '(fo fum)))
'(FEE FI)
[3]> (cdr *) ; * is the last returned value
((FEE FI))
(cdr (car ...)) 真的是 cdar,毫无疑问。