fugafuga.write

日々のログ

すごいH本 part16

高階関数を実装する

高階関数は関数を引数として受け取ることができるし、返り値として関数を返すこともできる。

関数を受け取ってそれを2回適用する高階関数

applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)

実行結果

*Main> applyTwice (+3) 10
16
*Main> applyTwice (++ "HOOOOO") "FOOOO"
"FOOOOHOOOOOHOOOOO"
*Main> applyTwice ("Strong" ++) "Zero"
"StrongStrongZero"
*Main> applyTwice (multThree 2 2) 9
144
*Main> applyTwice (3:) [1]
[3,3,1]

引数を1つ受け取って1つの値を返す関数を部分適用で作り出し、 それを applyTwice の1つ目の引数に設定している。

zipWith を実装する

zipWith は2つのリストを引数に取り、2つのリストの各要素に関数を適用することで、2つのリストを1つに結合する。

よくわからんのでまず関数の型シグネチャを見てみる

*Main> :t zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

実装

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' _ [] _ = [] -- リスト a が空
zipWith' _ _ [] = [] -- リスト b が空
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys

実行結果

*Main> zipWith' (+) [1,2,3] [4,5,6]
[5,7,9]
*Main> zipWith' max [1,2,3] [4,5,6]
[4,5,6]
*Main> zipWith' (++) ["aa","bb","cc"] ["xx","yy","zz"]
["aaxx","bbyy","cczz"]
*Main> zipWith' (*) (replicate 5 2) [1..]
[2,4,6,8,10]
*Main> zipWith' (zipWith' (*)) [[1,2,3],[3,5,6],[2,3,4]] [[3,2,2],[3,4,5],[5,4,3]]
[[3,4,6],[9,20,30],[10,12,12]]

最後のは難しいけど型考えたら「そうかー」となる。

flip を実装する

引数を入れ替えた関数を返すやつらしい

型シグネチャ

*Main> :t flip
flip :: (a -> b -> c) -> b -> a -> c

実装

flip' :: (a -> b -> c) -> (b -> a -> c)
flip' f = g
  where g x y = f y x

実装その2

flip' :: (a -> b -> c) -> b -> a -> c
flip' f y x = f x y

その2の方がシンプルになっている。関数がカリー化されていることを上手く使っているらしい。

用途がよくわからんので実行してゆく

*Main> zip [1,2,3,4,5] "hello"
[(1,'h'),(2,'e'),(3,'l'),(4,'l'),(5,'o')]
*Main> flip' zip [1,2,3,4,5] "hello"
[('h',1),('e',2),('l',3),('l',4),('o',5)]
*Main> zipWith div [2,2..] [10,8,6,4,2]
[0,0,0,0,1]
*Main> zipWith (flip' div) [2,2..] [10,8,6,4,2]
[5,4,3,2,1]

なるほど、そういうことかというのはわかるが使い所が不明

所感

いまいちflipがよくわからん。関数を変形できるところにメリットがあるのか?

偉い人教えてください...

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

  • 作者: MiranLipovaca
  • 出版社/メーカー: オーム社
  • 発売日: 2017/07/14
  • メディア: Kindle版
  • 購入: 4人 クリック: 9回
  • この商品を含むブログを見る