【closure】閉包。レキシカルクロージャとも言う。
静的スコープ(レキシカルスコープ)を実現するために必要となる。
関数内に出現する自由変数(関数内で宣言されていない変数)の解決の際、実行時の環境ではなく、関数を定義した環境の変数を参照できるようなデータ構造。
「推移的閉包【transitive closure】」とかのクロージャとは全く関係がないのに同じ名前なことが、言語を越えて学習者を無意味に悩ませている
以下のようなコードを考える(文法はJavaScript)
function makeCounter () { var count = 0; return f; function f () { return count++; } } var count = 10; var counter = makeCounter(); document.writeln(counter()); document.writeln(counter()); document.writeln(counter()); document.writeln(counter());
クロージャである(静的スコープ)とき、出力はこのようになる。
0 1 2 3
クロージャでない(動的スコープ)とき、出力はこのようになる。
10 11 12 13
Lispでは、方言によってクロージャを提供するかに違いがある。
Lispは、歴史的には動的スコープであり、Emacs Lispは動的スコープである。
Schemeは、クロージャ(静的スコープ)を採用した最初のLisp方言である。
Common Lispは、クロージャ(静的スコープ)を採用しているが、スペシャル変数によって動的スコープを利用する事もできる。
Emacs Lispでは、次のコードは、
(let ((count 0)) (defun get-count () (setq count (+ count 1)) count) (let ((count 10)) (print (get-count)) (print (get-count)) (print (get-count)) (print (get-count))))
このように出力される。
11 12 13 14
それに対し、等価な、次のSchemeのコードは、
(let ((count 0)) (define (get-count) (set! count (+ count 1)) count) (let ((count 10)) (print (get-count)) (print (get-count)) (print (get-count)) (print (get-count))))
このように出力される。
1 2 3 4
誰かが言っていたが、クロージャは並大抵の苦労じゃ実装できないらしい。