Haskell-部分適用
部分適用 (partial application) について
部分適用とは
部分適用とは、関数に対して全ての引数を一度に渡さず、一部の引数だけ渡すことができる仕組みです。
Haskellでは、関数に対してすべての引数を同時に渡さなくともエラーとなりません。
例えば、2つの引数をとる関数に対して1つだけ引数を渡しておいて、残りの引数をあとから渡すことができます。
これは、2つの引数を受け取る関数に対して引数を一つだけ渡すと、「1つの引数をとる関数」になるという仕組みに基づいています。
部分適用に変形する。
以下は、通常形式で記述した2つの引数を加算するadd関数です。
#!/usr/bin/env runghc
add :: Integer -> Integer -> Integer
add x y = x + y
main = print val
where
val = add 5 2
これを部分適用に変形します。
tmpはaddに「5」を渡して生成した関数であり、tmpは引数を一つとり「5」を加算する関数という意味になります。
tmpに「2」を渡すことで、加算結果として「7」を返します。
#!/usr/bin/env runghc
add :: Integer -> Integer -> Integer
add x y = x + y
main = print val
where
val = tmp 2
tmp = add 5
部分適用と高階関数の関係
Haskellでは、真の意味で2つ以上の引数をとる関数は存在しません。
あらゆる関数は「1つだけ引数をとって関数を返す関数」であるといえます。
この関数を返す関数とは「高階関数」を意味します。
つまり、Haskellでは複数の引数をとる関数は、全て高階関数であるといえます。
カリー化
カリー化(currying)とは
カリー化とは、複数の引数をとる関数を、引数が1つだけの高階関数に変換する操作です。
Haskellでは、2つの引数を受け取る関数に対して引数を一つだけ渡すと、「1つの引数をとる関数」になります。
関数を戻り値として返すことで、全ての関数を1つの引数の関数として表現することをカリー化といいます。
以下の関数addは、1つ目の引数xを受け取ったら引数1つyを受け取る関数を返し、yをその関数に適用して戻り値を返す関数という意味になります。
#!/usr/bin/env runghc
add :: Integer -> Integer -> Integer
add x y = x + y
main = do print $ (add 2) 5 -- カリー化
print $ add 2 5 -- カリー化しない
カリー化と部分適用の関係
カリー化と部分適用は混合されやすい概念ですが、同義ではありません。
両者は「カリー化が行えることで、あらゆる関数は引数を部分適用することができる」という関係です。
部分適用とは、複数の引数をとる関数に対して、一部の実引数を適用する操作のことです。これは、「固定値」を持った関数を作成することになります。
対して、カリー化では、引数への値の適用までは行いません。引数が1つだけの高階関数に変換する操作を指します。
セクション(section)
Haskellでは演算子を部分適用することも可能です。
部分適用を使って、引数を1つだけ渡した二項演算子のことをセクションといいます。
セクションの形式は以下の2通りがあります。
(演算子 式)
(式 演算子)
演算子の位置によって、意味が変化します。
以下のセクションは、「2で割る計算」と「2を割る計算」という意味になります。
Prelude> (/ 2) 4
2.0
Prelude> (2 /) 4
0.5