クロージャとブロック (追記)
今日になって、昨日の一連のエントリを読み直してみましたが、細かい話ですが注釈を入れさせて貰った方が良さそうな部分を発見してしまいました。
それなりに推敲しているつもりですが、私が書く場合は、やはり少し寝かせてからでないとダメですね。
昨日のエントリで、Scheme と対比させるコードとして、クロージャを持たない言語である Emacs Lisp を使いましたが、その理由として動的スコープ、有限エクステントを挙げています。
しかし、単に動的スコープというだけでなく、
- 動的スコープで、且つ環境を特定できる手段を持たないから。
としておかないとなりませんでした。
以前のエントリにも書きましたが、動的スコープであっても、特定の環境にのみ結び付けられる仕組みさえあれば良い筈だからです。shiro さんからご紹介頂いた The Function of FUNCTION in LISP or Why the FUNARG Problem Should be Called the Environment Problem (邦訳) でも、動的スコープの場合に function 特殊形式を利用して環境へのポインタを保持する手法について述べられています。
因みに、Emacs Lisp にクロージャが無いというのは、Emacs Lisp の Info (Node: Extent) にも、
Lispの方言のいくつかには『クロージャ』(closure)があります。それは関数のようなオブジェクトですが、追加の変数束縛を記録します。Emacs Lispにはクロージャはありません。
と、明確に書いてありますが、それじゃ仕方無いのかと言うと、Emacs Lisp 使い達が黙っている筈がありません。
昨日のエントリのコードですと、
;; cl を導入すれば、定義時に束縛された y が利用される。 (let (a1 a2 (y 5) f) (eval-when-compile (require 'cl)) (setq a1 '(1 2 3)) (setq a2 '(4 5)) (setq f (lexical-let ((y 2)) (lambda (x) (* x (setq y (+ y 1)))))) (let () (cons (mapcar f a1) (mapcar f a2)))) => ((3 8 15) 24 35)
という具合に、Common Lisp のエミュレートを行なう cl パッケージを利用することでクロージャとして動作させることができます。
ご存じの方が多いでしょうが、そもそも Emacs Lisp を使わない方も多いと思いますので、一応、紹介させて頂きました。