Circular data-structures not printing correctly?
If I :(setq p (list 1 2 3 4))
then,
(setq p (rplaca (cons 5 p) (cadddr p)))
shouldn't I get a circular data structure involving at least one "#1=" ?
On 9/2/08, Randall Blanchard <blancha2@earthlink.net> wrote: > If I : > > (setq p (list 1 2 3 4)) > > then, > > (setq p (rplaca (cons 5 p) (cadddr p))) > > shouldn't I get a circular data structure involving at least one "#1=" ? > Instead I get a "flat" data structure. Normally, you only get that kind of output when *print-circle* is bound to a non-NIL value (which is not the default because of the computational overhead involved). Bye, Erik.
Randall Blanchard wrote: > If I : > > (setq p (list 1 2 3 4)) > > then, > > (setq p (rplaca (cons 5 p) (cadddr p))) > > shouldn't I get a circular data structure involving at least one "#1=" ? No. You're creating a new pair, and changing the car of that pair to 4. There's no shared cons cell, much less any circularity. Sharing atoms is not sharing structure requiring #n= -- Chris Riesbeck Home page: http://www.cs.northwestern.edu/~riesbeck/ Calendar: http://calendar.yahoo.com/criesbeck
Chris Riesbeck writes: > > Randall Blanchard wrote: > > If I : > > > > (setq p (list 1 2 3 4)) > > > > then, > > > > (setq p (rplaca (cons 5 p) (cadddr p))) > > > > shouldn't I get a circular data structure involving at least one "#1=" ? > > No. You're creating a new pair, and changing the car of that pair to 4. > There's no shared cons cell, much less any circularity. Sharing atoms is > not sharing structure requiring #n= However, in the case of non interned atoms, #= references are still used when *PRINT-CIRCLE*. C/USER[37]> (let* ((a (list 'a #\+ 1 "i" #(b #\- 2 "ii"))) (b (append a a)) (*print-circle* t)) (print b) (values)) (A #\+ 1 #1="i" #2=#(B #\- 2 "ii") A #\+ 1 #1# #2#) C/USER[38]> The reason is that symbols, characters and numbers are immutable, and reading twice the same (string=) representation gives always the same (eql) object. C/USER[43]> (every (lambda (s) (eql (read-from-string s) (read-from-string s))) '("1" "a" "#\\c")) T Therefore there's no need to refer explicitely to the previous occurence. On the other hand, other atoms (most of them are not even atomic), are mutable, and not interned in anyways. Reading their representation again produces a distinct copy: C/USER[45]> (some (lambda (s) (eql (read-from-string s) (read-from-string s))) '("\"a\"" "#(a b c)" "#*10101010")) NIL So for these objects, it may be important to distinguish references to a unique objects, from occurence of a copy: C/USER[51]> (let* ((a (list (make-string 3 :initial-element #\a))) (b (append a a (list (make-string 3 :initial-element #\a))))) (let ((*print-circle* t)) (print b)) (let ((*print-circle* nil)) (print b)) (setf (aref (car a) 0) #\X) (let ((*print-circle* t)) (print b)) (let ((*print-circle* nil)) (print b)) (values)) (#1="aaa" #1# "aaa") ("aaa" "aaa" "aaa") (#1="Xaa" #1# "aaa") ("Xaa" "Xaa" "aaa") C/USER[52]> Oh, and finally, here is how you can make a circular list: C/USER[52]> (setf *print-circle* t) T C/USER[53]> (let ((a (list 1 2 3))) (rplacd (last a) a) ; notice that (last a) returns the last CONS cell. a) #1=(1 2 3 . #1#) C/USER[54]> Or a random circular structure: C/USER[55]> (let ((a (list 1 2 3))) (rplaca (cdr a) a) ; notice that (cdr a) returns aCONS cell.. a) #1=(1 #1# 3) C/USER[56]> (setf *print-circle* nil *print-length* nil *print-level* 4) 4 C/USER[57]> (let ((a (list 1 2 3))) (rplaca (cdr a) a) ; notice that (cdr a) returns aCONS cell.. a) (1 (1 (1 (1 # 3) 3) 3) 3) C/USER[58]> -- __Pascal Bourguignon__ http://www.informatimago.com/ HEALTH WARNING: Care should be taken when lifting this product, since its mass, and thus its weight, is dependent on its velocity relative to the user.