【问题标题】:Common Lisp quote behavior with car and cdr使用 car 和 cdr 的 Common Lisp 引用行为
【发布时间】:2013-06-30 23:54:55
【问题描述】:

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)

任何照明将不胜感激!

【问题讨论】:

    标签: lisp common-lisp cdr


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      在 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 消失了,但所有内部的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,毫无疑问。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-20
        • 1970-01-01
        • 1970-01-01
        • 2016-06-10
        • 2021-08-18
        • 1970-01-01
        • 1970-01-01
        • 2011-08-16
        相关资源
        最近更新 更多