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

関連ページ