ScalaとかHaskellとかの話。あとJavaとか

関数型言語について勉強中です。

クロージャーについて

2/8にScala関西ビギナーズという勉強会でLTをしてきました。
資料はこちらなのですが、

Java使いにとっての関数

LTではこういった関数

def outer(x:Int) = {
  var more = x
  (y:Int) => y + more
}

を定義し、P.15でクロージャーとは
「 引数で渡された変数以外の変数をさわれる関数のこと(ただしスコープ内の) 」という事で、「outerを実行すると(y+more)を実行する関数オブジェクトを取得。このオブジェクトがクロージャー」と説明しました。

ただ、だと「スコープ内外って?」という疑問もわきますし説明が不十分だったのと、いまいち自分の理解も怪しかったので、もう少しクロージャーについて調べてみました。

クロージャ - Wikipedia
Wikipediaの概要の説明をここで言いたいことに纏めるとこんな感じです。

「外側の関数の変数を参照するのがクロージャーで、クロージャーは外側の関数の実行時に生成される。クロージャーは外側の関数のスコープにある変数を全て参照できる。クロージャーはその変数を束縛する。」

なので上述の「ただしスコープ内の」というのは詳細には「外側の関数のスコープ内の」といえるかと思います。

クロージャーが変数を束縛している様子は英語版のクロージャーのページの例がわかりやすかったのでscalaで書きなおしてみました。

f:id:amkt922:20140219165737p:plain

counterを実行すると、int型のyを受け取り外側の関数の変数xに足して画面にxを表示するクロージャーを返します。
counter1_incrementとcounter2_incrementの2つのクロージャーを生成します。
それぞれの動作は相互に影響することなく処理していることがわかります。
またcounter1_increment、counter2_incrementの処理をした後にcounter3_incrementを生成し実行しても、それまでの
counter1_incrementの結果に影響されていることはありません。
f:id:amkt922:20140220131715p:plain

つまり外側の関数の変数xを取り込んでいるって事ですかね?
「変数xを束縛している」という事で、このような性質をもった関数オブジェクトの事をクロージャーという事になるんだということなんですね。