在Lisp中打印defstruct

4

我有一个在Lisp中定义的非常简单的数据结构:

;;Data structure for a person

(defstruct person
  (name nil)
  (age 0)
  (siblings nil :type list))   ;; Siblings is a list of person objects

我随后实例化了几个人对象:
(setf person-a (make-person :name 'Tim :age 23))
(setf person-b (make-person :name 'Sally :age 21))
(setf person-c (make-person :name 'Louis :age 24))

我接下来将描述兄弟姐妹们(假设他们都是彼此的兄弟姐妹):
(setf (person-siblings person-a) (list person-b person-c))
(setf (person-siblings person-b) (list person-a person-c))
(setf (person-siblings person-c) (list person-b person-a))

我该如何打印已经实例化和修改的对象的信息呢?我查看了关于defstructprint-objectprint-function选项,但我无法弄清楚如何正确地打印我的对象。使用类似以下代码的方式:

(print person-a)

发送我的ACL解释器进入无限循环。
1个回答

7
常见的Lisp语言中有一个变量用于控制递归结构的打印:*print-circle*。在您的Lisp环境中,它可能默认为假(nil)(如SBCL和clisp中),这可能会导致无限循环。如果您将其设置为t,则应该可以打印出您的结构。
(setf *print-circle* t)

我用以下文件进行了测试:
(defstruct person
  (name nil)
  (age 0)
  (siblings nil :type list))

(setf person-a (make-person :name 'Tim :age 23))
(setf person-b (make-person :name 'Sally :age 21))
(setf person-c (make-person :name 'Louis :age 24))

(setf (person-siblings person-a) (list person-b person-c))
(setf (person-siblings person-b) (list person-a person-c))
(setf (person-siblings person-c) (list person-a person-b))

(setf *print-circle* t)
(format t "~a~&" person-a)
(format t "~a~&" person-b)
(format t "~a~&" person-c)

(print person-a)
(print person-b)
(print person-c)

这是运行该代码的记录:
> sbcl
This is SBCL 1.0.55, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (load "defstruct.lisp")

#1=#S(PERSON
        :NAME TIM
        :AGE 23
        :SIBLINGS (#2=#S(PERSON
                         :NAME SALLY
                         :AGE 21
                         :SIBLINGS (#1#
                                    #3=#S(PERSON
                                          :NAME LOUIS
                                          :AGE 24
                                          :SIBLINGS (#1# #2#))))
                   #3#))
#1=#S(PERSON
      :NAME SALLY
      :AGE 21
      :SIBLINGS (#2=#S(PERSON
                       :NAME TIM
                       :AGE 23
                       :SIBLINGS (#1#
                                  #3=#S(PERSON
                                        :NAME LOUIS
                                        :AGE 24
                                        :SIBLINGS (#2# #1#))))
                 #3#))
#1=#S(PERSON
      :NAME LOUIS
      :AGE 24
      :SIBLINGS (#2=#S(PERSON
                       :NAME TIM
                       :AGE 23
                       :SIBLINGS (#3=#S(PERSON
                                        :NAME SALLY
                                        :AGE 21
                                        :SIBLINGS (#2# #1#))
                                  #1#))
                 #3#))

#1=#S(PERSON
      :NAME TIM
      :AGE 23
      :SIBLINGS (#2=#S(PERSON
                       :NAME SALLY
                       :AGE 21
                       :SIBLINGS (#1#
                                  #3=#S(PERSON
                                        :NAME LOUIS
                                        :AGE 24
                                        :SIBLINGS (#1# #2#))))
                 #3#)) 
#1=#S(PERSON
      :NAME SALLY
      :AGE 21
      :SIBLINGS (#2=#S(PERSON
                       :NAME TIM
                       :AGE 23
                       :SIBLINGS (#1#
                                  #3=#S(PERSON
                                        :NAME LOUIS
                                        :AGE 24
                                        :SIBLINGS (#2# #1#))))
                 #3#)) 
#1=#S(PERSON
      :NAME LOUIS
      :AGE 24
      :SIBLINGS (#2=#S(PERSON
                       :NAME TIM
                       :AGE 23
                       :SIBLINGS (#3=#S(PERSON
                                        :NAME SALLY
                                        :AGE 21
                                        :SIBLINGS (#2# #1#))
                                  #1#))
                 #3#)) 
T
* (sb-ext:quit)

如果我将*print-circle* nil,那么我会得到一个堆栈溢出错误(在sbcl中为SB-KERNEL::CONTROL-STACK-EXHAUSTED)。
希望对你有所帮助,
Kyle

这非常有帮助。我对您的格式有疑问。您能进一步解释一下这三行格式吗?我还想知道为什么每个人对象都会打印两次。 - Isthan
1
表单(格式nil“...”...)类似于print和princ,可以在控制台上打印。format是Common Lisp的printf/sprintf等效函数。我的代码使用format分别打印每个人,然后再用print打印一次,以展示递归结构的打印成功。 - Kyle Burton
1
这是一个古老的答案,但是,你是否知道为什么它在sbcl中默认设置为nil?这是一个相当不直观的默认设置。 - violet_white

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接