【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
誰かが言っていたが、クロージャは並大抵の苦労じゃ実装できないらしい。