(defun test (x) #'(lambda (y) (setq x (* y x)) x)) ;;(defun test (x) ;; (function (lambda (y) (setq x (* y x)) x))) ;; と同じ.この関数testを引数を与えて呼ぶと 新たな関数が定義されることになる. たとえば,引数として1と2を与えたものを 以下のように作れば,
> (setq x1 (test 1)) #<CLOSURE :LAMBDA (Y) (SETQ X (* Y X)) X> > (setq x2 (test 2)) #<CLOSURE :LAMBDA (Y) (SETQ X (* Y X)) X>変数x1, x2が表すものは別の関数クロージャとなる.これらの関数クロージャ はfuncallにより呼び出すことが可能である.以下のようにx1に対して同じ引 数5を与えても計算結果は5, 25と変わってきている.それは,関数testの引数 xに計算結果が保存されるという形の関数定義になっているからである.
> (funcall x1 5) 5 > (funcall x1 5) 25 > (funcall x2 5) 10 > (funcall x2 5) 50 > (funcall x1 5) 125 > (funcall x2 5) 250このように,クロージャを返す関数の場合,関数への引数はクロージャの中に 保存される.つまり,その引数はクロージャの評価環境として残り続けると いうわけである.では,どの範囲のものが残り続けるかといえば,そのクロージャ が定義された関数時の局所変数である. たとえば,局所変数を作るletを用いて,
(defun let-closure (z) (let ((x 1)) #'(lambda (y) (setq x (* x y) z (* z y)) (list x y z))))という関数let-closureを定義すると,(let-clousre 1)や(let-closure 2)な どのように呼び出すことでそれぞれ異なるクロージャが定義される.
> (setq l1 (let-closure 1)) #<CLOSURE :LAMBDA (Y) (SETQ X (* X Y) Z (* Z Y)) (LIST X Y Z)> > (setq l2 (let-closure 2)) #<CLOSURE :LAMBDA (Y) (SETQ X (* X Y) Z (* Z Y)) (LIST X Y Z)> ;;; 古いFranz CL(Allegro CL 3.0.1.beta)の場合. > (setq l1 (let-closure 1)) (EXCL::.LEXICAL-CLOSURE. (LAMBDA (Y) (SETQ X (* X Y) Z (* Z Y)) (LIST X Y Z)) ((X . 1) (Z . 1)) NIL ((LET-CLOSURE . EXCL::INVALID)) NIL) > (setq l2 (let-closure 2)) (EXCL::.LEXICAL-CLOSURE. (LAMBDA (Y) (SETQ X (* X Y) Z (* Z Y)) (LIST X Y Z)) ((X . 1) (Z . 2)) NIL ((LET-CLOSURE . EXCL::INVALID)) NIL)この関数クロージャの生成時においては,変数x,z が局所変数であり, これら二つの変数の値が保存された形でクロージャが生成されている. l1,l2をそれぞれfuncallにより実行すると以下のようにx,y,zの値を 返す.
> (funcall l1 5) (5 5 5) > (funcall l1 5) (25 5 25) > (funcall l2 5) (5 5 10) > (funcall l2 5) (25 5 50) > (funcall l1 5) (125 5 125) > (funcall l2 5) (125 5 250)