2

I know that scheme is a lexically scoped/statically scoped language, but I don't understand why these two blocks of code return different results.

   (define a 100)
   (let ((z 20))
      (lambda (a b) (+ a b)) a z)

20

 (define a 100)
 (let ((z 20)) 
      (lambda (a b) (+ a b)) z a)

100

Clayton
  • 43
  • 4
  • You should explain what you think should happen in both examples, step-by-step. In particular, how are the bodies of each let form evaluated? – coredump Oct 03 '16 at 22:08
  • Do you think you are passing `a` and `z` in different orders to the `lambda`? `let` returns the value of its final form, which is `z` (which you `let`-bound to 20) in the first case, and `a` (which you `define`d as 100) in the second case. – Dan Oct 03 '16 at 22:55

1 Answers1

10

Both your code blocks have similar syntax. A lexical variable z with two lines of dead code and a expression in tail position that becomes the result of the let. eg.

(let ((z 20))
  (lambda (a b) (+ a b)) ; evaluates to a procedure and thrown away
  a                      ; evaluated to 100 and thrown away 
  z)                     ; evaluated to 20. in tail so the result of let

The second is very similar:

 (let ((z 20)) 
   (lambda (a b) (+ a b)) ; evaluates to a procedure and thrown away
   z                      ; evaluated to 20 and thrown away
   a)                     ; evaluated to 100. In tail so the result of let

Notice that the lambda that evaluates to procedures are never applied (called). To call them eg. with the other expressions as arguments you get completely different result:

(let ((z 20))
  ; calls the anonymous lambda with agruments a and z
  ((lambda (a b) (+ a b)) a z)) ; ==> 120

Parentheses matters in this language. Too few and you get separate expressions where the last is the result. Too many and you are accidentally applying values that are not procedures.

Also note that in a dynamically scoped lisp you would have got the same result. In this however:

(define n 100)
(define (make-incer n)
  (lambda (x) 
    (+ n x)))

(define inc10 (make-incer 10))
(inc10 5) 
; ==> 15 (lexically scoped) 
; ==> 105 (dynamicly scoped)

The reason is that dymamicly coped languages don't have closures and thus n doesn't exist when make-incer has returned the procedure and thus n is the global binding or closer call time binding like here:

(let ((n 5))
  (inc10 20)) 
; ==> 30 (lexically scoped)
; ==> 25 (dynamically scoped)
Sylwester
  • 47,942
  • 4
  • 47
  • 79