はじめに
経緯
Scala関西サミット20181日目のセッションでScalaにおける関数型プログラミングについて学ばせていただきたました。
これがわかりやすかったものの、使わないと忘れるので書き残しておこう思います。
この記事で分かるかもしれないこと
初学者の私が感じるScalaの難しいなと思うところは以下2点です。
- Scalaの言語仕様。
- 関数型プログラミングが何かわからない。
そのうちScalaの関数型プログラミングってどんな感じなのかというのがわかったら嬉しいです。
本題
関数とは
プログラミングに触れる以前の私が学んでいた関数は数学の関数です。
例えば、1次関数f(x) = x + 1
これをコードで表すならば。
def f(x : Int) = x + 1
そのままですね。
関数定義に=
を使うのも、なるほど数学と一緒です。
また数学がどうだったか忘れてしまいましたが、Scalaは関数の定義に当たる式を複数の文・式で表すことができます。
{}
で囲まれた部分を一つの式としてみなすことができます。
このとき、最後に評価された式の評価結果が関数の戻り値です。
def f(x: Int) = {
val y = x + 1
y * 2
}
関数型プログラミング
気をつけるポイント
- 変更可能な変数を使わない
- 再代入も使わない
- ループなどの命令形の制御を使わない
関数型プログラミングとはこれだ!!という定義はあんまりないようですが、上で挙げた3点に気をつけると良いみたいです。
複雑な関数を定義する
1次関数のような簡単な関数なら簡単に定義できそうですが、もっと複雑な関数を作りたいときはどうしましょうか。
フィボナッチ数列におけるn番目の数を求める関数を例に説明します。
法則を見つける
フィボナッチ数列の場合
f(1) = 1
f(2) = 1
f(3) = f(1) + f(2)
f(4) = f(2) + f(3)
このように書き出してみると、最初の2数は1で、それ以降は前の2数を足した数になりそうですね。そりゃそういう数列だものね。
パターンとして考えられるのは以下の3通り。私はプログラミングをしているの?数学をしているの?
n = 1 のとき f(n) = 1
n = 2 のとき f(n) = 1
n >= 3のとき f(n) = f(n - 2) + f(n - 1)
Scalaのコードに落とし込む
上で見つけた法則をコードにそのまま落とし込みます。
def f(n: Int): Int = n match {
case 1 => 1
case 2 => 1
case _ => f(n - 1) + f(n - 2)
}
まんまじゃないか!でもこれがいわゆる関数型プログラミングみたいです。
※関数名や仮引数の名前は各々分かりやすいように変えたほうが良いと思います。
補足
上のコードでは再帰を使っていますが、このコードだとスタックオーバーフローを起こしてしまうそうです。
末尾再帰という書き方があるみたいなので、また調べて追記したいと思います。
さいごに
今までプログラミングをやっていた中で、最も数学感を感じました。高校数学の漸化式みたい!って思ったところもありました。
これはこれで、仕事の息抜きにクイズ感覚でやってみると面白いかもしれません。にわかでごめんないさい。