クロージャーの定義
wikipedia:クロージャ などを見ると(できることは同じようですが)クロージャーの定義にはいろいろあるようです。ここでも定義しておいた方が良いと思われるので、ここで使うものを定義しておきます。
式は以下のものから構成されます。
- 定数
- 変数
- 算術演算子、比較演算子を使った 、 という式
- 通常の関数適用
- クロージャー
- クロージャー適用
- let = in
- subst = in
- def ( ) = in
- fun ( ) =
- if then else
変数と式を対応させたものを環境と呼ぶことにします。環境はポインターを使わないとうまく定義できないので、ポインターを使って定義します。ポインターを使わない方法は後で検討します。ポインターを Haskell のリストのような形で表します。
集合 によってインデックスが付けられた集合 で の元は変数 、式 、ポインター( の元または をポインターと呼ぶことにします) の組 であるものを考えます。 を ポインター が参照する内容と呼ぶことにします。 と の組を と書いて、 と書くことにします。これをリストのような形で書きます。 のとき 、 のとき と書くことにします。
環境を(ポインターとして)
- または
- ( は変数、 は式、 は環境)
と帰納的に定義します。
ある環境 で変数 に対応する式 を以下のように帰納的に定義します。
- のとき
- のとき
- のとき
ある環境 に対して、変数 に対応する式を で置き換えた環境 を以下のように帰納的に定義します。
- のとき
- のとき (ポインターの参照する内容が置き換えられます)
- のとき
ポインターの参照する内容が置き換えられるというのは、 をポインター と見たときに、上に書いたポインターの集合 でインデックスが付けられた の元 を同じ に対応する別の で置き換えた を、これ以降(後述のブロックでこれより後の部分)は の代わりに使うということを表します。
ある環境 での式 の値(数値または真理値) を考えます。
定数 の値
定数 の値は です。
変数 の値
変数 の値は です。
算術演算子、比較演算子を使った 、 という式の値
の値は となります。 は に対応する数値の演算で または が のときは値は とします。 の値は となります。 は に対応する数値の演算で が のときは値は とします。
let = in の値
は変数、 と は式です。
です。
subst = in の値
は変数、 と は式です。
です。 は置き換えられた環境で評価されます。
def ( ) = in
関数定義を表します。 は変数(関数名)、 は変数、 と は式です。
です。
ここで です。再帰的定義のために の定義が追加されています。 はクロージャーです。
となります。このときクロージャーが持っている環境 を使います。
fun ( ) =
無名関数を表します。 は変数、 は式です。
です。
if then else
、、 は式です。 は が真のとき 、 が偽のとき となります。
ブロックの記法
- let = in
- subst = in
- def ( ) = in
が連続するとき
let v = x; subst v' = x' def f ( w1, w2, w_3 ) = x'' y
のようにブロックとして表すことができます。このブログの例のコードでは、C# のコードとして書きやすいためブロックで表しています。
変数の変更が不可能なクロージャーとポインターの調査
サーバーのプログラムを変数の変更が可能なクロージャーを使って書くと、サーバーのプログラムを更新することはブラウザーのプログラムを更新することと同様にできるという例を見てきました。これによってブラウザーのプログラムが複数あるときにも「同じことを二度書かない」ことを実現することができます。
これを変数の変更が不可能なクロージャーで書くとどうなるかということを考えていきます。これは、サーバーのプログラムを変更するとそれを使っているプログラムが使えなくなるので、それを避けることができるのかどうか調べるためです。
サーバーのプログラムが無限に続くものだ考えると、それを変数の変更が不可能なクロージャーで書くことはできないということになりますが、考え方を変えることによってできるのかどうかを調べてみます。サーバーのプログラムが有限の回数で終わるとすれば、変数の変更が不可能なクロージャーで書くことはできます。そのプログラムの無限に続く「バージョンアップ」のような考え方でできるかどうか調べてみます。