使用汽车和cdr的Common Lisp引用行为

时间:2013-06-30 23:54:56

标签: lisp common-lisp cdr

Lisp的初学者。我正在研究“Common Lisp:一个温和的介绍”,我遇到了这种我不理解的行为。这是在clisp:

[57]> (cdar '((fee fi) '(fo fum)))
(FI)
[58]> (cdar '('(fee fi) '(fo fum)))
((FEE FI))

第一个表达式(第57行)对我有意义。它获得了((费用fi)(fo fum))的CAR的CDR,即(费用fi)的CDR。但是58号线上发生了什么?我原以为它会给我完全相同的东西,(FI)。但它给了我一份清单清单?谁能帮我理解发生了什么?

更令人惊讶的是,如果我用两个表达式中的每个表达式执行这些操作,当(费用fi)不加引号时我会收到错误:

[72]> (car '((fee fi) '(fo fum)))
(FEE FI)
[73]> (cdr (FEE FI))

*** - EVAL: undefined function FEE

但是当我引用(费用fi)时,我得到了正确的结果,这反映了我的第一个结果:

[77]> (car '('(fee fi) '(fo fum)))
'(FEE FI)
[78]> (cdr '(FEE FI))
(FI)

非常感谢任何照明!

2 个答案:

答案 0 :(得分:9)

'字符只是缩写:'something在读取时扩展为(quote something)。因此:

(cdar '('(fee fi) '(fo fum)))

实际上是:

(cdar (quote ((quote (fee fi)) (quote (fo fum)))))

第一个quote阻止评估其内容,因此其余部分只是文字列表和符号,因此更有用的表示形式是:

(cdar '((quote (fee fi)) (quote (fo fum))))

然后CAR(quote (fee fi))CDR((fee fi))

答案 1 :(得分:1)

在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 quotequote-reader系统函数。列表也很特别:

[5]> (get-macro-character #\()
#<SYSTEM-FUNCTION SYSTEM::LPAR-READER> ;
NIL

读完所有内容后,将评估结果。这是“read-eval-print loop”“read-eval”部分,即REPL。评估a quote form(quote ...)的结果就是其中的内容。 Iow顶部quote消失,但所有内部quote仍然存在。

没有报价,一切都会被评估。因此,要评估(cdr (FEE FI)),必须评估表单(FEE FI),如果结果列表,则会返回该列表的cdr


您可以try to define另一种表示文字数据的方式,例如[ ... ]括号代表(quote ( ... ))。转换可以将内部括号视为简单括号。然后两个

> (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,对此毫无疑问。