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.

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

    Regarding your second example explanation: you are mixing up dynamic extend and lexical scope.

    If only lexical scope would be available for this second source code, then bar could not see the value of 20 for *x* and always would print 10. (Try this example in C/C++, which only uses lexical scope, see below). But since *x* is a special variable and rules of dynamic extend apply, bar sees the value of 20, when called by foo and therefore prints 20.

    SBCL returned for both examples the value of 20 on my system, btw.

    C-Example:

    #include 
    
    int x = 10;
    
    void bar();
    
    void foo() { int x = 20; bar(); }
    
    void bar(){ printf("%i\n",x); }
    
    void main() { foo(); }
    // this program prints 10, as expected
    
  • MrJCraft@alien.topB
    link
    fedilink
    English
    arrow-up
    1
    ·
    10 months ago

    in your first example I get 20
    I got the same result in
    ABCL, SBCL, CCL, GCL, and MKCL

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

    You have done something which has made x be globally special. Restart your SBCL and it will be fine.