2

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

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

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

更令人惊讶的是,如果我在两个表达式中分别执行这些操作,那么在 (fee fi) 未引用时会出现错误:

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

*** - EVAL: undefined function FEE

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

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

任何照明将不胜感激!

4

2 回答 2

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是 then (quote (fee fi)), the of CDRthat 是((fee fi))

于 2013-07-01T00:02:34.830 回答
1

在 Lisp 可以评估某些东西之前,必须先读入它。Readoperation 接受一些数据的文本表示并将其转换为 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

所以句话背后一些东西。一个quote-reader系统函数。列表也很特别:

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

读取所有内容后,然后评估结果。这就是“read-eval-print loop”的“read-eval”部分,即 REPL。评估报价结果,是其中的任何内容。IOW 顶部消失了,但所有内部s 仍然存在。(quote ...)quotequote

没有报价,一切都会被评估。所以要评估,必须评估(cdr (FEE FI))表单,如果它产生一个列表,则该列表将被返回。(FEE FI)cdr


您可以尝试定义另一种表示文字数据的方式,例如用[ ... ]括号表示(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,毫无疑问。

于 2013-07-01T07:51:50.997 回答