While playing around with graphs, I got a curious error I didn't quite understand. The code below reproduces the problem.
;; 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))
I got the same result with SBCL and Clozure. Setting *print-length*
to a manageable value did not work.
So my questions is: Why doesn't this code create the same kind of infinite printing loop as a circular list (i.e., no stack overflow and stoppable with Ctrl-C). Any input is appreciated.
Thanks, Paulo
*print-length*
controls the number of elements in a list. You're looking for *print-level*
. This works fine for me.
(let ((*print-level* 3))
(format t "~W~%" a))
;; Output: #S(NODE :PROPERTIES (:NAME A)
;; :LINKS (#S(NODE :PROPERTIES # :LINKS #)))
Alternatively, you could use *print-circle*
to detect cycles and print them in an even nicer way.
(let ((*print-circle* t))
(format t "~W~%" a))
;; Output: #1=#S(NODE :PROPERTIES (:NAME A)
;; :LINKS (#S(NODE :PROPERTIES (:NAME B) :LINKS (#1#))))
Here, it actually detects the cycle and prints #1#
, a reference to the #1=
to show that it's the same object.