(defun new-account (name &optional (balance 0.00) (interest-rate .06)) #'(lambda (message) (case message (withdraw #'(lambda (amt) (if (<= amt balance) (decf balance amt) 'insufficient-funds))) (deposit #'(lambda (amt) (incf balance amt))) (balance #'(lambda () balance)) (name #'(lambda () name)) (interest #'(lambda () (incf balance (* interest-rate balance)))))))このような,新しい口座を開く手続きnew-accountを定義する. ここでは,アカウントが関数クロージャになっている. そして,その関数クロージャは,メッセージを引数と してそのメッセージに応じた処理を行う場合分けを行う 手続きとなっている. 使い方は,
> (setq acc (new-account "abc")) #<Interpreted Closure ...> > (funcall acc 'name) #<Interpreted Closure ...> > (apply (funcall acc 'name) nil) "abc" > (funcall acc 'balance) #<Interpreted Closure ...> > (apply (funcall acc 'balance) nil) 0.0 > (apply (funcall acc 'deposit) '(10)) 10.0 > (apply (funcall acc 'balance) nil) 10.0という具合に,accにnew-accountで作られるクロージャを代入する. このクロージャには,balanceとinterest-rateが閉じ込められている. このクロージャの中の関数がmessageを受け取って, そのmessage内容によってcaseで分けた手続きを返す. その返された手続きにmessageに応じた引数をapplyすると その手続きが実行されて,目的のものを得ることができる. 上の例で,10だけdepositした後,balanceを見るとbalanceが増えていること がわかる.クロージャの中にbalanceが保存されているからである.