札幌Scala勉強会#12
コップ本第8章の「関数とクロージャー」をやりました。以下メモ。
一人前の存在としての関数
first-class function. wikipediaでは第一級関数。
値としての関数
function values.
関数リテラルを実行時にインスタンス化したもの。
FunctionNトレイトを拡張する何らかのクラスのインスタンス。
コップ本にはN(0-22)と書いてあるが、Scaladocを見ても、Function1, Function2しか見当たらない。
部分適用された関数
def sum(a:Int, b:Int, c:Int) = a + b + c val a = sum _
sum _ という部分適用関数式から、渡されていない3個の整数パラメータを受け取る関数インスタンスを作成する。
a(1,2,3) #=> 6
これは、a.apply(1,2,3) の短縮形である
someNumbers.foreach( println _ )
は、
someNumbers.foreach( println )
と書ける。
foreachの引数は関数呼び出しが必要とされる場所だから。
val a = sum _
は
val a = sum
と書けない。これは、右辺が関数呼び出しを保証していないから。
val a:Int => Int = sum
とは書ける。意味違うけど。
クロージャー
自由変数の束縛を「取り込んで」、関数リテラルを「閉じる」
(x:Int) => x + more
moreは自由変数(free variables)。xは束縛変数(bound variables)。
この関数リテラルから実行時に作られるインスタンスをクロージャーと呼ぶ。
閉じた項 : 自由変数のない関数リテラル ← 厳密な意味ではクロージャーではない
開いた項 : 自由変数を含んだ関数リテラル ← 実行時に作られた関数オブジェクト(インスタンス)がクロージャー
プログラムの実行とともに実体が変わっていく変数にアクセスする場合
クロージャーが作成されたときにアクティブだったインスタンスを使う。
scala> def makeInc(more:Int) = (x:Int) => x + more makeInc: (more: Int)Int => Int scala> var i = 1 i: Int = 1 scala> val inc1 = makeInc(i) #=> moreに1が入る。moreの束縛として、1をつかんでクロージャーが作成される inc1: Int => Int = <function1> scala> i = 99 i: Int = 99 scala> val inc2 = makeInc(i) #=> moreに99が入る。 inc2: Int => Int = <function1> scala> inc1(100) res0: Int = 101 scala> inc2(100) res1: Int = 199
連続パラメーター
echo(arr: _*)って分かりづらいね。
末尾再帰
- 単純再帰しか最適化できない
- メモ化しているわけではない
- 同じ関数を呼び出す直接的な再帰のみ