为什么交联的析构函数会导致堆栈溢出?

时间:2018-07-03 00:37:45

标签: data-structures common-lisp sbcl clozure-cl

在玩图时,出现了一个我不太理解的奇怪错误。下面的代码重现了问题。

;; Define struct to store a node with links to other nodes.
(defstruct node properties links)

;; Make two nodes
(setf a (make-node :properties '(:name a))
      b (make-node :properties '(:name b)))

;; Create link from b to a. This works fine...
(push b (node-links a))

;; ... but this crosslink makes lisp chase its own tail for a while and then crash with a stack overflow.
(push a (node-links b))

我在SBCL和Clozure上得到了相同的结果。将*print-length*设置为可管理的值无效。

所以我的问题是:为什么此代码不创建与循环列表相同类型的无限打印循环(即,没有堆栈溢出并且可以使用Ctrl-C停止)。任何输入表示赞赏。

谢谢,  保罗

1 个答案:

答案 0 :(得分:6)

*print-length*控制列表中元素的数量。您正在寻找*print-level*。这对我来说很好。

(let ((*print-level* 3))
  (format t "~W~%" a))
;; Output: #S(NODE :PROPERTIES (:NAME A)
;;  :LINKS (#S(NODE :PROPERTIES # :LINKS #)))

或者,您可以使用*print-circle*来检测周期并以更好的方式打印周期。

(let ((*print-circle* t))
  (format t "~W~%" a))
;; Output: #1=#S(NODE :PROPERTIES (:NAME A)
;;  :LINKS (#S(NODE :PROPERTIES (:NAME B) :LINKS (#1#))))

在这里,它实际上检测到循环并打印#1#,它是对#1=的引用,以表明它是同一对象。