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)
非常感谢任何照明!
答案 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 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
消失,但所有内部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
,对此毫无疑问。