我正在尝试将一个通用的 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
执行时
(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))))
对于结构实例,结果是人类可读的,但不是 lisp 可读的。
我是否需要以某种方式禁用
:print-function
(如果这是问题所在)?
如果您为
: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)
...))))
...)
将正确运行,因为
print-unreadable-object
被定义为在 *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)))))
现在
> *print-readably*
nil
> (let ((*print-readably* t))
(print (make-foo)))
#S(foo :x nil)
#<foo x = nil 8010058923>
当然,所有
:print-function
和:print-object
机制所做的就是为您在print-object
上定义程式化方法。来自defstruct
:
和:print-function
选项指定应为结构名称类型的结构生成:print-object
方法。print-object
在 CLOS 之前(当
:print-object
不存在时):print-function
以更神奇的方式做了一些事情,但这一切都被 CLOS 大大简化了。