(漂亮)在Common Lisp中打印大对象

mob*_*eng 5 lisp printing sbcl common-lisp read-eval-print-loop

如果我有一个类,例如包含几个将填充向量的插槽,则通常会出现此问题.如果我想让这个类的对象或多或少透明,我实现print-object它.在这里我遇到了问题:

  1. 如果我在一行中打印所有内容,REPL的启发式方法不足以确定如何在多行中排列可打印部分,从而导致所有内容向右移动(请参见下面的示例).
  2. 如果我决定手动将输出分成多行,我就会遇到如何正确缩进所有内容的问题,这样如果此对象是另一个对象的一部分,则会保留缩进(请参阅下面的示例以获得更清晰).

这是代码.考虑两个类:

(defclass foo ()
  ((slot1 :initarg :slot1)
   (slot2 :initarg :slot2)))

(defclass bar ()
  ((foo-slot :initarg :foo)))
Run Code Online (Sandbox Code Playgroud)

我有以下几个例子:

(defparameter *foo*
  (make-instance 'foo
    :slot1 '(a b c d e f g h i j k l m n o p q r s t u v)
    :slot2 #(1 2 3 4 5 6 7 8)))


(defparameter *bar*
  (make-instance 'bar
    :foo *foo*))
Run Code Online (Sandbox Code Playgroud)

我想看到的是这样的:

> *bar*
#<BAR
  foo-slot = #<FOO
                slot1 = (A B C D E F G H I J K L M N O P Q R S T U V)
                slot2 = #(1 2 3 4 5 6 7 8)>>
Run Code Online (Sandbox Code Playgroud)

案例1:在一行中打印所有内容

print-object这些类的定义可以是这样的:

(defmethod print-object ((obj foo) out)
  (with-slots (slot1 slot2) obj
    (print-unreadable-object (obj out :type t)
      (format out "slot1 = ~A slot2 = ~A" slot1 slot2))))

(defmethod print-object ((obj bar) out)
  (with-slots (foo-slot) obj
    (print-unreadable-object (obj out :type t)
      (format out "foo-slot = ~A" foo-slot))))
Run Code Online (Sandbox Code Playgroud)

但是,它们的可打印表示不太理想:

> *foo*
#<FOO slot1 = (A B C D E F G H I J K L M N O P Q R S T U V) slot2 = #(1 2 3 4 5
                                                                      6 7 8)>

> *bar*
#<BAR foo-slot = #<FOO slot1 = (A B C D E F G H I J K L M N O P Q R S T U V) slot2 = #(1
                                                                                       2
                                                                                       3
                                                                                       4
                                                                                       5
                                                                                       6
                                                                                       7
                                                                                       8)>>
Run Code Online (Sandbox Code Playgroud)

案例2:尝试多行打印

使用多行打印,我不知道如何控制缩进:

(defmethod print-object ((obj foo) out)
  (with-slots (slot1 slot2) obj
    (print-unreadable-object (obj out :type t)
      (format out "~%~Tslot1 = ~A~%~Tslot2 = ~A" slot1 slot2))))

(defmethod print-object ((obj bar) out)
  (with-slots (foo-slot) obj
    (print-unreadable-object (obj out :type t)
      (format out "~%~Tfoo-slot = ~A" foo-slot))))
Run Code Online (Sandbox Code Playgroud)

因此,*foo*打印确定,但*bar*不是:

> *foo*
#<FOO 
  slot1 = (A B C D E F G H I J K L M N O P Q R S T U V)
  slot2 = #(1 2 3 4 5 6 7 8)>
*bar*
#<BAR 
  foo-slot = #<FOO 
  slot1 = (A B C D E F G H I J K L M N O P Q R S T U V)
  slot2 = #(1 2 3 4 5 6 7 8)>>
Run Code Online (Sandbox Code Playgroud)

在过去,我试图玩print-indent,但没有成功(我看不到它的任何影响,也许没有正确使用它,SBCL 1.2.14).

是否有(最好是简单的)方法来解决这个问题?

jki*_*ski 7

尝试这样的事情(可能需要更多抛光):

(defmethod print-object ((obj foo) out)
  (with-slots (slot1 slot2) obj
    (print-unreadable-object (obj out :type t)
      (format out "~<~:_slot1 = ~A ~:_slot2 = ~A~:>" (list slot1 slot2)))))

(defmethod print-object ((obj bar) out)
  (with-slots (foo-slot) obj
    (print-unreadable-object (obj out :type t)
      (format out "~<~:_foo-slot = ~A~:>" (list foo-slot)))))
Run Code Online (Sandbox Code Playgroud)

它使用~<~:>,它们是逻辑块的格式化操作.然后它使用~:_,这是一个条件换行符.您应该阅读相关的hyperspec部分.