@tako_programingの忘備録とか

男子高校生の日常の忘備録

Scalaの多相関数のお勉強

Scalaでのプログラミングを学ぶ場合、教材は良いものが結構あって、「Scalaスケーラブルプログラミング第三版」や「Functional Programming in Scala」の和訳本などが有名です。また、ドワンゴさんの新人研修テキストがネット上で無料で読めたはずなので、お金を払って書籍を買うほどでもないという人は最初に読んでみるといいかもしれないです。今回の記事は関数型プログラミング全般において重要な要素の1つでもある関数型プログラミングについてScalaで勉強したときのメモです。


多相関数とは、1つのデータ型に対してのみ操作を行う単相関数に対して、いかなる型に対しても操作を行うことのできる関数のことをいいます。Scalaの標準ライブラリには、たくさんの多相関数が存在します。たとえば以下に示す関数はString型の文字列の先頭文字を返す単相関数です。

def returnHead(str: String): Char = str.head

この関数はString型の値しか引数にもらうことができません。単一の文字であるChar型の値しか返すことができません。これを全てのいかなる型のリストでも引数としてうけとることができ、そのリストにつつまれている型の値を返り値として返すことができる多相関数として定義しなおしてみましょう。

def returnHead[T](arg: List[T]): T = arg.head

これであらゆるT型のリストを引数としてうけとり、その先頭要素を返り値として返すことができるようになります。(ただ、この関数にStringの値を直接渡すとtype mismatchでエラーが起こります。この関数のままで対応するにはStringの値にtoList関数を使いChar型のリストに変換する必要があります。)ためしに使ってみましょう。

scala> returnHead(List(1, 2, 3, 4, 5))
res: Int = 1

と、こうなります。 一応このreturnHead関数の説明をしておきます(定義のままですが)。まず、最初の方は通常の単相関数と変わりありません。そのあと[T]がでてきます。この[T]は型パラメーターと呼ばれます。型パラメータは[A, B, C]のように区切って複数持たせることができます。また、この名前は通常の変数や引数と同じようにどのような名前をつけても機能しますが、慣例として大文字1つの名前をつけることが多いようです。 また、この型パラメータの一つずつを型変数といい、型シグネチャの他の箇所から自由に参照することができます。今回定義した関数では、arg: List[T]のように関数のパラメータリストのなかで一度参照しています。今回の関数では一箇所からしか型変数を参照していませんが、複数箇所から参照することが可能です(というかむしろそういう使い方をするのが普通な気がします)。

def example[T](arg1: T, arg2: T => List[T]): List[T] = arg2(arg1)

上の例の関数は、型変数Tを関数の引数リストで二度参照しています。第二引数の関数に第一引数のT型の値を適用した値を返します。試しに使ってみると以下のようになります。

scala> example(4, (x: Int) => { List(x, x+1, x+2) })
res1: List[Int] = List(4, 5, 6)

ここまでくれば説明するまでもないとは思いますが、example4(x: String) => { List(x + "0", x + "1", x + "2") }でも渡そうものならtype mismatchで怒られてしまいます。Tは1つの関数の中で一貫して同じ型のことを示します。


これらのような多相関数は色々な動作をより抽象的に表現することが可能になります。抽象化することで再利用性が向上しますし、より関数型プログラミングのスタイルに近づくということみたいです。