Haskellのお勉強 その10
値としての関数
関数型プログラミング言語における関数ってのは値です。
値は変数を束縛することができます。したがって、関数は変数を束縛することができます。
また、関数は値なので、他の関数に引数として渡すことができます。
というわけで、高階関数の復習です。
Prelude> let square n = n^2 Prelude> map square [1..5] [1,4,9,16,25]
んでもって、square関数がここでしか使わないような関数の場合、
いちいちsquareって変数に束縛する必要はないですよね。
というわけで、Haskellでは無名関数という、名無しの関数を適宜作ることができる。
Prelude>map (\n -> n^2) [1..5] [1,4,9,16,25]
無名関数は複数のパターンマッチを列挙することができない以外は
通常の関数束縛と同様のパターンマッチを適用することができる。
たとえばタプルパターン
Prelude>map (\(x,y) -> x * y) [(2,3),(3,5)] [6,15]
そんでもってデータコンストラクタパターン
Prelude> Import Char Prelude Char>map (\(x:xs) -> toUpper x : xs) ["hogehoge","puyopuyo","pikopiko","aiueo"] ["Hogehoge","Puyopuyo","Pikopiko","Aiueo"]
関数合成
Haskellでは関数を合成することができます。なにやら難しそうな感じもするが、別段難しくはない。
(.)関数の定義は以下のようになっている。
(.) :: (b -> c) -> (a -> b) -> (a -> c)
つまりこの定義では、(.)関数の第一引数の型が「(b -> c)」、
第二引数の型が「(a -> b)」、戻り値の型が「(a -> c)」である。
つまり(.)関数を用いて関すを合成をするには「第二引数で与えられた関数の戻り値の型(ここではb型)が、
第一引数で与えられた関数の引数として有効な型(つまりb型ね)でなければならない」
ということを表現しているわけですな。
つまり、(.)関数を用いた場合、f . gでは、
gを適用した後にfが適用されることになる。やってみる。
Prelude> reverse . reverse $ "abc" "abc" Prelude> (\xs -> (length . lines) xs) "aaaa\nbbbb\ncc\ndd" 4
おお、ちゃんと関数が合成されとりますね。
無名関数の場合でもちゃんと合成できてます。はい。
合成関数(.)の左右のオペランドを逆にした逆合成関数(>.>)を作成してみる。
(>.>) :: (a - b) -> (b -> c) -> (a -> c) (>.>) = flip (.)
こんな感じの定義になる。
んで、試してみる
Prelude> let f = (2+) --section Prelude> let g = (3*) --section Prelude> let (>.>) = flip (.) Prelude> (f.g) 3 11 Prelude> (g.f) 3 15 Prelude> (g>.>f) 3 11
おぉ簡単だーね。ただ逆になるだけだけど、こいつは面白いw
ちゃんと、(f.g) 3も (g>.>f) 3も「3倍してから2を加える関数」になってますね。
ちなみに、flip関数は、引数を2つ適用する関数を与えると、
引数の順番をひっくり返した関数を返してくれるという関数。うほっ!こりゃ便利w
flip :: (a -> b -> c) -> b -> a -> c flip f x y = f y x
お疲れなので、今日はここまで。