car和cdr的常见Lisp引用行为



Lisp初学者。我正在读《常见的Lisp:一个温和的介绍》,我遇到了这种我不理解的行为。这是clisp:

[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

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

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

任何照明都将不胜感激!

'字符只是一个缩写:'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))

在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

所以在引用后面有一些东西。quote-reader系统功能。列表也很特别:

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

读取完所有内容后,将对结果进行评估。这是REPL中"read-eval-print loop"的"read-eval"部分。评估引用表单(quote ...)的结果是它内部的内容。IOW顶部的quote消失,但所有内部的quote都保留下来。

没有报价,一切都会被评估。因此,要评估(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,毫无疑问。

相关内容

  • 没有找到相关文章

最新更新