はじめに
N予備校で「Scala応用」コースを受講しています。
今回から関数型プログラミングについてです。
関数型プログラミング
外部の状態を変化させない関数だけでプログラミングを行うこと
外部の状態を変化させることを、副作用という。
副作用のある関数
変数を変更する
オブジェクトが持っているフィールドの値を書き換える
例外やエラーを発生させる etc.
参照透過性
値と式が交換できるような関数
def square(n: Int) = n * n
同じ値を入れたら必ず同じ結果になることが保証されたもの、かな。
正直テキストよりもこっちの方がまだわかりやすい。
関数
val add = new Function2[Int, Int, Int] {
def apply(x: Int, y: Int): Int = x + y
}
Function0
〜Function22
まではインスタンス化して表現できるらしい。
apply
メソッドを実装することで、x.apply(y)
が x(y)
で書くことができる。
シンタックスシュガー
val add = (x: Int, y: Int) => x + y
要は無名関数のこと。
カリー化
名前を見るたびに「日本印度化計画」が流れます。
val addCurried = (x: Int) => ((y: Int) => x + y)
メソッドチェーンのような感じで書ける。
呼び出しは、
addCurried(100)(200)
再起関数の注意点
def series(n: Int): Int = {
if (n == 0) {
0
} else {
series(n - 1) + n
}
}
series(10000)
などで実行すると、
StackOverflowError
が発生してしまう可能性がある。
末尾再帰最適化
再帰関数の呼び出しが必ず関数の末尾に来るような記述としておくことで 内部的にループ処理に書き換えてくれる
@tailrec
アノテーションを利用すると、最適化されていない時はコンパイルエラーになる。
@tailrec
def series(n: Int): Int =
まとめ
段々難しくなってきてますが、こうやってまとめると頭の中も整理されていく気がします。ここからしばらく関数型プログラミングが続きます。