I’m learning common lisp and the subtleties of scoping really troubles me. For example, running this piece of (“double-let”) code

(let ((x 10))
  (funcall
    (let((x 20))
      (lambda () x ))))

gives me 20 in Clisp and 10 in SBCL. I’m not even sure this is a dynamic/lexical scoping issue, because a typical example that demonstrates scoping would concern special variables defined with defvar/defparameter, like

(defvar *x* 10)
(defun foo ()
  (let ((*x* 20))
    (bar)))
(defun bar ()
  (print *x*))
(foo)

a dynamic-binding language is supposed to give 10, and lexical-binding one 20. (BTW I tested this with Clisp and SBCL, both gave me 10.)

So what is causing different behavior with the “double-let” example? Does SBCL not create an closure with the lambda function?

I would appreciate it if someone would explain, or point out references.

  • Patrick-Poitras@alien.topB
    link
    fedilink
    English
    arrow-up
    1
    ·
    10 months ago

    My understanding was that the first example should give 20 on SBCL. I tried it and it gave me 20.

    On your second example, on SBCL, I got 20 for foo and 10 for bar.

    * (defvar *x* 10)
    *X*
    * (defun foo ()
         (let ((*x* 20))
             (bar)))
    ; in: DEFUN FOO
    ;     (BAR)
    ; 
    ; caught STYLE-WARNING:
    ;   undefined function: COMMON-LISP-USER::BAR
    ; 
    ; compilation unit finished
    ;   Undefined function:
    ;     BAR
    ;   caught 1 STYLE-WARNING condition
    FOO
    * (defun bar ()
         (print *x*))
    BAR
    * (foo)
    
    20 
    20
    * (bar)
    
    10 
    10
    

    Not sure if that’s helpful in any way. Is there some context we’re missing?

    • Rockola_HEL@alien.topB
      link
      fedilink
      English
      arrow-up
      1
      ·
      10 months ago

      SBCL 2.2.9.debian gives 20 for the 1st example, as expected. OP might want to double-check that result.