;;; Closure examples from class. ;;; NOTE: this is GCL, a Common Lisp, which is _lexically scoped_. ;;; For dynamic scoping, see Emacs LISP (Elisp) examples. ;; Let's see what happens if we leave a free variable in a lambda body: >(lambda (x) (+ x y)) (LAMBDA-CLOSURE () () () (X) (+ X Y)) ;; It creates something :) How will this evaluate? >(funcall (lambda (x) (+ x y)) 2) Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by +. Condition in + [or a callee]: INTERNAL-SIMPLE-TYPE-ERROR: (A B C) is not of type NUMBER: Broken at +. Type :H for Help. 1 Return to top level. >>1 ;; Oops, we already have a Y and it's a list. We could re-setq it to a number, but let's simplify the lambda instead: Top level. >(funcall (lambda (x) y) 2) (A B C) >y (A B C) >(setq y 10000000) 10000000 >(funcall (lambda (x) y) 2) 10000000 ;; Same for function bodies: >(defun foo (x) (+ y x)) FOO >(foo 1) 10000001 >(setq y 20000) 20000 >(foo 1) 20001 ;; So, we get the value of the global Y, whatever it is at the moment. ;; So far this doesn't appear different from Elisp. ;; But watch this: >(let ((z 5)) (defun foo (x) z)) FOO >(foo 4) 5 >(setq z 1000) 1000 >(foo 4) 5 ;; FOO doesn't care about the changes in the global Z---it was "closed" over the let's local Z instead! ;; Same deal for lambdas. (This isn't surprising, since in GCL DEFUN is actually a macro that uses LAMBDA inside it). >(setq f (let ((z 5)) (lambda (x) z))) (LAMBDA-CLOSURE ((Z 5)) () () (X) Z) ;; <--- note how the closure is shown; compare with LAMBDA-CLOSURE above. >(FUNCALL f 1) 5 >(setq z 1000) 1000 >(FUNCALL f 1) 5 >(let ((z 5)) (defun foo () z)) FOO >(foo) 5 >(setq z 1000) 1000 >(foo) 5 >(let ((z 5)) (defun foo () z)) FOO >z 1000 ;; Will this change if we use Z's full package name? >(let ((z 5)) (defun foo () COMMON-LISP-USER::z)) FOO >(foo) 5 ; <-- No. It's still LET's lexically scoped "local" variable. >z 1000 ;; Another example. Test this in Elisp to see the difference (or see ;; emacs-dynamic-and-static-bindings.txt and ;; emacs-dynamic-and-static-bindings-more.txt >(let ((y 7)) (defun sc-test (x) (list x y)) ) SC-TEST >(sc-test 1) (1 7) >y 10000000 >(setq y 1000) 1000 >(sc-test 1) (1 7) >(sc-test 2) (2 7) >(sc-test 5) (5 7)