Thanks Peter, that makes sense. I guess I didn't understand dynamic scope as well as I had thought.
I changed the code inside the (let* ...) as follows, and this works:
(defun testit () (with-ltk () (let* ((canv (setf *cvs* (make-instance 'canvas :width 200 :height 200))) (b (make-instance 'button :master nil :text "Do it!" :command (lambda () (draw-circle 100 100 20 :red)))))
(format t "A Canvas is ~a~%" *cvs*) (pack canv) (pack b) (draw-circle 100 100 40 :blue))))
This makes it more obvious (to me..) that the canvas bound inside the (let*...) is different from the global one. I guess this is how the ltk::ltktest example is able to work, e.g. the start and stop buttons.
I bet this wont be the last time I am bitten by that problem.
Thanks,
Neil