スマートフォン用の表示で見る

クロージャ

【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では、方言によってクロージャを提供するかに違いがある。

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

その他

誰かが言っていたが、クロージャは並大抵の苦労じゃ実装できないらしい。