【问题标题】:Common Lisp: How to quote parenthese in SBCLCommon Lisp:如何在 SBCL 中引用括号
【发布时间】:2015-04-30 02:37:25
【问题描述】:

在 Common Lisp 中,特殊运算符 quote 使后面的任何内容都未计算,例如

(quote a) -> a
(quote {}) -> {}

但是为什么表单 (quote ()) 给了我 nil?我正在使用 SBCL 1.2.6,这就是我在 REPL 中得到的:

CL-USER> (quote ())
NIL

关于这个问题的更多信息:这是来自 PCL 第 24 章的一些代码

(defun as-keyword (sym)
  (intern (string sym) :keyword))

(defun slot->defclass-slot (spec)
  (let ((name (first spec)))
    `(,name :initarg ,(as-keyword name) :accessor ,name)))

(defmacro define-binary-class (name slots)
  `(defclass ,name ()
     ,(mapcar #'slot->defclass-slot slots)))

当宏展开为以下代码时:

(define-binary-class id3-tag
    ((major-version)))

(DEFCLASS ID3-TAG NIL
      ((MAJOR-VERSION :INITARG :MAJOR-VERSION :ACCESSOR MAJOR-VERSION)))

在类名 ID3-TAG 之后是 NIL 而不是 ()

【问题讨论】:

  • @FrédéricHamidi 谢谢 :) 我以前没有注意到这一点。
  • @FrédéricHamidi 你能添加你的评论作为答案吗?因此可以将其标记为正确答案。谢谢。

标签: lisp common-lisp sbcl quote


【解决方案1】:

nil() 是表达同一概念的两种方式(空列表)。

传统上,nil 用于强调布尔值“false”而不是空列表,而() 则相反。

通用 LISP HyperSpec says:

() ['nil], n.用于书写符号 nil 的另一种表示法,使用 强调将nil用作空列表

【讨论】:

    【解决方案2】:

    您的观察是由于一个对象具有多个表示。在 Common Lisp 中,阅读器(阅读代码和阅读表达式)将文本解析为结构和数据。当它是数据时,作者可以再次将其打印出来,但它不会确切知道数据在最初读入时是如何表示的。即使有多种表示形式,作者也会按照默认值和设置以一种方式打印一个对象对于那个对象。

    如您所见,nilNILnILNiL、...、'nil'NIL()'() 都被读取为同一个对象.我不确定标准究竟应该如何规定它的默认表示形式,所以我猜有些实现会选择NILnil 甚至() 之一。

    使用 cons 表示取决于 cdr 是否为 cons/nil:

    '(a . nil)        ; ==> (a)
    '(a . (b . c))    ; ==> (a b . c)
    '(a . (b . nil))  ; ==> (a b)
    

    通过数字,读者可以得到有关您正在使用的基数的提示。如果文本中没有使用任何基础,它将使用 *read-base* 是什么:

    (let ((*read-base* 2)) ; read numbers as boolean
      (read-from-string "(10 #x10)")) ; ==> (2 16) 
    

    #x 告诉读者将其余部分解释为十六进制值。现在,如果您的 print-base 为 4,则上述答案将显示为 (2 100)

    总而言之.. Common Lisp 中的单个值可能有几种良好的表示形式,并且它们都将产生相同的值。值的打印方式将遵循生成它们的函数的实现、设置甚至参数。无论是接受什么作为值,还是以不同的方式可视化该值,都无法说明该值实际上是如何在内部存储的。

    【讨论】:

    • 谢谢 :) BTW,对于“现在,如果您的 print-base 为 4,则上述答案将被可视化为 (2 100)。”,您的意思是设置 print -base 到 4?因为我试过 (let ((*read-base* 2) (*print-base* 4)) (read-from-string "(10 #x10)")) 但结果仍然是(2 16)
    • @seki-shi 如果您使用printlet 中打印结果,您将打印(2 100),然后返回(2 16),因为*print-base* 不同。要让 REPL 在 base 4 中打印,您需要使用 setf/setq,因为 REPL 显示的结果是本地绑定消失后 let 的结果。例如(setf *print-base* 4)
    猜你喜欢
    • 1970-01-01
    • 2017-05-19
    • 1970-01-01
    • 1970-01-01
    • 2016-10-27
    • 2011-09-22
    • 1970-01-01
    • 2017-02-27
    • 2015-09-30
    相关资源
    最近更新 更多