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
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)