はじめに
純粋関数型プログラミング言語であるHaskellを参考に、以下の3つの構成で高階関数についてまとめていく予定です。
- カリー化関数
- 高階関数の実践
- ラムダ式
本投稿はカリー化関数の概念についてまとめていきます。(別記事は随時更新予定)
高階関数
Haskellの関数は、引数として関数を取ったり返り値として関数を返したりすることが可能で、このような関数は高階関数と呼ばれます。
カリー化関数
Haskellのすべての関数は、複数の引数を取る関数が定義されているように見えますが、公式には引数は一つだけ取るようになっています。
これは関数がカリー化されることによって、複数の引数を取るような関数が定義できているということです。
まずは例を見るのがわかりやすいと思うので、max関数を用いて説明したいと思います。
Prelude> max 4 5
5
Prelude> (max 4) 5
5
※Prelude>: Haskellの対話モード
maxは二つの関数を引数にとって、大きい方の数を返す関数に見えます。上記の例では、4と5を引数に取り、大きい数字である5を返しています。
これは正確には二つの引数を取って結果を返しているのではなく、以下の挙動になっています
-
maxが最初に4を適用し、別の関数を返り値として返す - 次に返り値である関数が
5を適用し、最終的な数値である5を返す
これが上記の例のmax 4 5と(max 4) 5が等価である理由です。
このように、カリー化関数とは、常に一つの引数を受け取り、次の引数を受け取るための関数を返す関数のことになります。
次は、自作関数を用いて説明します。
multTree :: Int -> Int -> Int -> Int
multTree x y z = x * y * z
これは、3つの引数を受け取り、3つの数を掛けた数を返します。
正確に言うと、3つの引数を受け取り、3つの数を掛けた数を返すように見える関数です。
この関数を実行してみます
Prelude> multTree 3 5 9
135
挙動は以下のようになります。
- 最初に
multTreeが3を適応し、Int -> Int -> Int型の関数を返す - 次に
Int -> Int -> Int型の関数が5を適応し、3と5を掛けた数を返す関数Int -> Intを返す - 最後に
9を受け取り、3と5と9を掛けた139を返す
Prelude> let multTwo = multTree 9
Prelude> :t multTwo
multiTwo :: Int -> Int -> Int
Prelude> let muitOne = multTwo 3
Prelude> :t muitOne
muitOne :: Int -> Int
※:t: 型を調べるコマンド
Swiftから見るカリー化関数
Swiftは様々なプログラミングパラダイムを備えており、関数型プログラミングのアプローチが可能となっています。
Swiftからカリー化関数を見ていきます。
まずは、二つの引数の積を返す関数を定義したいと思います。
通常なら以下の定義をすることが多いと思います。
func multiple(_ x: Int, _ y: Int) -> Int {
return x * y
}
multiple(3, 5)//15
この関数をカリー化した関数が以下になります。
func multiple(_ x: Int) -> (Int) -> Int {
return { y in x * y }
}
multiple(3)(5)//15
一つの引数を取る関数の連続になっています。
カリー化してない場合と比較すると、一度に1つの引数に関数を適用するか、2つに適用するかを選択できますね。引数を一つにした場合は以下のように使い回すことができます。
let multClosure = multiple(3)
multClosure(5)//15
multClosure(4)//12
同様にHaskellにおいても、異なる関数を簡単に扱うことができます。
Prelude> multTwo 3 2
162
Prelude> muitOne 5
135
このようにカリー化された関数は抽象度が高く、異なる機能を持つ関数を簡単に作り出せます。
これがカリー化することのメリットと言えますね。
カリー化関数をこのように部分適応することで、関数を簡単に合成することができるので複雑なコードを、関数を使って再構築可能な小さなパーツに分解することができます。
今回は簡単な数式で紹介したので、実践的なイメージがしにくいと思いますが、次回はより実践的な例を用いて高階関数の理解を深めていきたいと思います。