Common Lisp 中结构的 :print-function 和 *print-readously* 之间的干扰?

dav*_*ugh 1 hashtable sbcl common-lisp writefile data-structures

我正在尝试将一个常见的 Lisp 结构以可读的方式打印到一个文件中,以便稍后可以将其读回。SBCL 似乎有一些相当复杂的内置工具,用于以可读方式打印复杂对象,这可以避免编写专门的打印对象方法。

我的结构是否有可能:print-function干扰*print-readably*

(defstruct (problem-state (:conc-name problem-state.) (:print-function print-problem-state) (:copier nil))
  "A planning state including the current propositional database."
  (name nil :type symbol)  ;last action executed
  (instantiations nil :type list)  ;from last action effect
  (happenings nil :type list)  ;a list of (object (next-index next-time next-direction)) pairs
  (time 0.0 :type real)
  (value 0.0 :type real)
  (heuristic 0.0 :type real)
  (idb (make-hash-table) :type hash-table)  ;integer hash table of propositions
  (hidb (make-hash-table) :type hash-table))  ;integer table for happening events
Run Code Online (Sandbox Code Playgroud)

执行时

(defun save (object file)
  "Saves an object to a file so it can be read in later."
  (with-open-file (out-stream file :direction :output)
    (let ((*print-readably* t))
      (pprint object out-stream))))
Run Code Online (Sandbox Code Playgroud)

对于结构实例,结果是人类可读的,但不是 Lisp 可读的。

我是否需要以某种方式禁用:print-function(如果这是问题)?

ign*_*ens 6

如果您提供:print-function:print-object选项defstruct,则您指定的打印机将用于打印该类的对象。 该函数负责正确处理打印机控制变量。 特别是,这意味着如果*print-readably*为真,则必须以可读方式打印对象,或者如果不愿意或无法这样做,则发出错误信号:它不应该简单地以不可读的方式打印对象,更不应该绑定或分配给*print-readably*或类似的东西那。

print-unreadable-object可以帮助您纠正此行为:

(defstruct (foo
            (:print-function (lambda (f s d)
                               (declare (ignore d))
                               (print-unreadable-object (f s :type t :identity t)
                                 ...))))
  ...)
Run Code Online (Sandbox Code Playgroud)

将表现正确,正如print-unreadable-object定义的那样,如果为 true,则发出适当的错误信号*print-readably*

如果您希望能够在需要时可读地打印结构,但在其他情况下不可读,则使用:print-function:print-object机制相对难以做到这一点。你的函数显然没有得到这个正确的结果:我怀疑很少有人这样做。

幸运的是,有一个简单的答案,即不使用这些选项,而是定义方法print-object

(defstruct foo
  x)

(defmethod print-object ((f foo) s)
  (if *print-readably*
      (call-next-method)
    (print-unreadable-object (f s :type t :identity t)
      (format s "x = ~A" (foo-x f)))))
Run Code Online (Sandbox Code Playgroud)

现在

> *print-readably*
nil

> (let ((*print-readably* t))
    (print (make-foo)))

#S(foo :x nil) 
#<foo x = nil 8010058923>
Run Code Online (Sandbox Code Playgroud)

当然,所有:print-function:print-object机制所做的就是为您定义风格化的方法print-object。从defstruct

:print-function选项:print-object指定print-object应生成结构名称类型的结构的方法。

在 CLOS 之前(当时:print-object还不存在):print-function以更深刻的神奇方式做了一些事情,但这一切都被 CLOS 大大简化了。