クロージャについて少し考えてみました。

クロージャについて色々と考えてみました。
以前にも書いたのですが、そもそも Gauche をインストールした目的の一つに、クロージャの動作をもっと理解したいという目的があったので。

で、色々と shiro さんが公開されているドキュメントを読み返したり、Gauche 上で試行錯誤しながら、これまでの私の解釈には誤りがあったと思う様になりました。

これまでの私の理解では、クロージャとは、

  • クロージャは、ファーストクラスのオブジェクトである。なので、名前も付けられるし、関数の引数や戻り値としても利用できる。
  • クロージャには、(そのクロージャ生成時の) 環境が閉じ込められている。
  • クロージャ実行時に参照される環境は、実行時点のものではなく、クロージャ自身に閉じ込めてある環境になる。

というものでした。

これらの認識自体には誤りはないと思っている (誤りがあったらツッコミをお願いしたいです。> 識者の方々) のですが、これらが「クロージャという機構を実現するために用意されたもの」、という解釈をしていたところが何か違うと思う様になったのです。
この解釈は、特別意識していた訳ではないのですが、漠然と感じていたものです。
ひょっとすると、この感覚は、elispクロージャが使えず、cl パッケージを require してクロージャを使っていたりしたことが関係してるのかもしれません。つまり cl パッケージによってクロージャ機構を持ち込んだ、と感じていたのではないかと。

しかし、Scheme に触れていて、scheme に於けるクロージャは、幾つかの言語仕様による副作用の様なものだと感じる様になりました。その幾つかの言語仕様とは、

  • 手続き (lambda) は第一級計算要素 (ファーストクラスオブジェクト) である。
  • レキシカルスコープである。
  • 手続きの定義はトップレベルだけでなく、式の内部 (ボディ部) の冒頭でも可能である。(lambda はどこにでも書けますし)

といった辺りでしょうか。
これらの仕様は、特にクロージャを導入するためのものではない筈です。
しかし、これらの仕様が組み合わさると、あら不思議、手続きはクロージャとして利用できるものになっているよ、という具合でしょうか。

例えば、レキシカルスコープであって、トップレベル以外で手続きが定義可能 (まあ、lambda 式が書ければ良い訳ですが) なことから、定義部分から可視範囲にある自由変数へのアクセスが可能なところとか。
それを実現するために、手続き生成時点のスタックフレームを、生成された手続きが利用可能な期間中は保持しておくところとか。

こんな諸々のことからクロージャっていう機構が実現されているんだなあ、と勝手に解釈しています。
何かおかしなことを言っている様であれば識者の方々からツッコんで頂けるととても有難いです。