in SBCL why does setting *print-circle* to T in LET in common lisp not work, but SETF does print circular list fine?

33 Views Asked by At

I noticed that if I setf *print-circle* to T, then it prints circular list:

CL-USER> (setf *print-circle* t)
T
CL-USER> (let ((x (list 1)))
           (setf (cdr x) x)
            x)
#1=(1 . #1#)

But if I try using let instead to set *print-circle*, it hangs indefinitely.

CL-USER> (setf *print-circle* nil)
NIL
CL-USER> (let ((*print-circle* t)
               (x (list 1)))
           (setf (cdr x) x)
            x)
;; hangs indefinitely

What gives? I thought *print-circle* was a special "dynamically binding" variable, and thus using let will be able to temporarily bind it?

1

There are 1 best solutions below

0
xdavidliu On

It's because the printing is only done by the REPL after the let is evaluated, in which case the temporary setting of *print-circle* is already gone.

To get the effect I'm looking for, I need to make sure the printing is done inside the let:

CL-USER> (setf *print-circle* nil)
NIL
CL-USER> (let ((*print-circle* t)
               (x (list 1)))
           (setf (cdr x) x)
           (prin1 x)
           nil)
#1=(1 . #1#)
NIL
CL-USER>

Note that last nil after (prin1 x) is important, since without it, the repl will still attempt to evaluate then print the value of (prin1 x) outside the LET, and thus get stuck again