wvogel日記

自分用の技術備忘録が多めです.

カリー化と部分適用

 部分適用は、カリー化によって可能となる。
では、カリー化とは。
  すべての関数は一引数の関数として扱うこと。

f :: Num a => a -> a -> a

と定義された関数があるとき、fは2引数の関数である。
これに、例えば Numクラスに属する型の値 x を適用すると、(これが部分適用)
値を適用された関数は、fとは異なる関数として表現できる。

f x :: Num a => a -> a

となる。

実際にGHCiで実験してみる。
まず、関数 f を、以下のように定義

f :: Num a => a -> a -> a
f x y = x + y
Prelude> :t f
f :: Num a => a -> a -> a

Prelude> let x = 2
Prelude> :t f x
f x :: Integer -> Integer

このようになります。
もしここで

f 123 456

のようにすると、これは、
まず f に123を適用。
  →f y = 123 + y のように、一つの引数を適用し、関数を生成。
    → 456 を適用。
のような流れを追う。

Haskellでは、多分すべての関数はカリー化が可能。(どうなんだろ)
そして部分適用によって得られるのは値。
なので、以下のようなことも可能
まずはソースコード

module CurryTest where

myany :: Char -> String -> Bool
myany _ [] = False
myany c (s:str) = if c == s then True else myany c str

myany' :: Char -> (String -> Bool)
myany' c = myany c

そしてGHCiで実行。

*CurryTest> myany 's' "Haskell"
True
*CurryTest> :t myany' 's'
myany' 's' :: String -> Bool
*CurryTest> myany' 's' "Haskell"
True

Haskell使う過程で、誰もが一度は見たことがあると思われる

map (+2) numberlist

も、部分適用によってカリー化された関数をリストの各要素に適用しているのと同じ。


また、コメントをもらいましたが、
タプルを引数に取る関数

g :: (a,b) -> b -> a

のような関数があったときに、

g' :: a -> b -> b -> a

のように変換することも、これは、複数のデータを展開し、上で扱ってきたような関数と同等にすることでカリー化していることになるようです。