I am trying to understand concepts of lexical and dynamic scoping and the differences between them. Let's take a look at the following code:
(let ((a 1)
(b 2))
(letrec ((f (lambda () F))
(g (lambda (c) G)))
(lambda (d)
(+ (f) (g b)))))
For expressions F and G, which variables are at lexical scope of (lambda(d)...)
?
(lambda(d)...)
has d
as bound variable and f
, g
a
b
and all of the global scope as free variables.
EDIT
Just to demonstrate the code in Scheme and some other language where the same bindings are dynamic. Since neither of your functions call each other you might as well keep them in the same let
:
(define test
(let ((a 1)
(b 2)
(f (lambda () F))
(g (lambda (c) G)))
(lambda (d)
(+ (f) (g b)))))
;; for the test we need the F and G defined
(define F 10)
(define G 20)
(test 4) ; ==> 30 (aka (+ F G))
What happens is that when the lambda
gets evaluated the variables it uses from the lexical scope lives on even after the let
is gone. In a dymaic scope this isn't true:
(test 4)
; ERROR f: unbound identifier
The reason for this is while a
, b
, f
and g
existed when the lamba was evaluated none of the variables get captured like in lexical scope and thus when the procedure test
is made none of the local variables exist anymore. In fact you might as well write it like this:
;; in a dynamic lisp this s the same
(define test
(lambda (d)
(+ (f) (g b))))
And you must make sure the variable exist when you call the function (aka dynamic)
(define g (lambda (v) 1337))
(define f (lambda () 3.1415927))
(define b 13)
(test 4) ; ==> 1340.1415927
Now if you were to add the above definitions in the global scope and keep the original definition you'd still get 30
since a lexical lisp uses the closer lexical bindings rather than the global ones.
Another great example is this:
(define x 10)
(define (test v)
(+ x v))
(let ((x 20))
(test 10))
; ==> ?
In a lexical lisp the result would be always 20
since test
does not have any idea of the let
since it is not in its lexical scope. It's x
is always the global bindings x
. In a dymamic lisp the x
from the let
is the closest one from the runtime point of view which would result in 30
since the x
in test
is the same as the x
in the let
and it shadows the global x
.