2

尝试不以标准列表表示法打印 conses,而是始终以点对形式打印,以最小的努力,我以这种方式重新定义了print-object该方法:

(defmethod print-object((c cons) str)
  (format str "(~a . ~a)" (car c) (cdr c)))

但是对于不同的实现效果是不同的。

在 Clozure CL 和 LispWorks Personal 中,结果是我所期待的:

CL-USER 1 > (defmethod print-object((c cons) str)
                (format str "(~a . ~a)" (car c) (cdr c)))
#<STANDARD-METHOD PRINT-OBJECT NIL (CONS . (T . NIL)) 200A45AB>

CL-USER 2 > '(a b c )
(A . (B . (C . NIL)))

而在 SBCL 和 AllegroCLexpress 中,列表的打印方式没有任何变化:

* (defmethod print-object((c cons) str)
     (format str "(~a . ~a)" (car c) (cdr c)))

#<STANDARD-METHOD PRINT-OBJECT (CONS T) {10051EBC53}>
* '(a b c)

(A B C)

所以,我想知道这是否是由于语言规范中的一些歧义,如果这种行为被明确声明为未指定,如果这是由于 REPL 与包的某些交互,或者最后,如果有实现就这个定义而言是正确的,而其他的则不正确。最后要注意的是,在 SLIME 中给出这样的定义会对 SLIME 本身造成严重破坏!

有人可以阐明这些差异,并提出一种替代方法(如果存在的话,那么问题较小)来实现我的目标?

4

2 回答 2

4

CLHS 11.1.2.1.2列出了在 common lisp 包中更改内容的限制——这似乎与情况 19 相冲突。

除非明确允许,否则如果对 COMMON-LISP 包的外部符号执行以下任何操作,则后果是不确定的:

...

  1. 当所有参数都是标准化类的直接实例时,为标准化通用函数定义一个方法。

仅当*print-pretty*非零时的部分解决方法是使用漂亮的打印调度表

;(in-package cl-user)
(set-pprint-dispatch 'cons (lambda (s obj) (format s "(~A . ~A)" (car obj) (cdr obj))))
NIL
;(in-package cl-user)
(let ((*print-pretty* t)) (print (list 1 2 3)))

(1 . (2 . (3 . NIL)))
(1 2 3)
;(in-package cl-user)
于 2015-08-09T19:55:51.900 回答
2

标题有点误导。SBCL 没有print-objectconses 的方法。所以你不能重新定义它。出于某种原因,它允许您定义这样的方法,但它的打印机不会调用它。

AFAIK,SBCL 不支持print-object内置类型的用户定义方法。打印机不会调用它们。如果您查看打印机源,它正在使用一个TYPE-CASE构造来为不同的数据类型调用各种打印函数。

您可以在 SBCL 中为 CLOS 类定义print-object方法,它们将被调用。

这与 ANSI CL 不兼容吗?也许。至少不提供print-object方法的部分应该是不兼容的。这仍然不意味着人们可以改变它们......

根据方法定义所有/大多数/许多类(包括内置类)的打印是否有用PRINT-OBJECT。是的。

于 2015-08-09T19:30:59.630 回答