Haskell 勉強メモ9
セクション
中置関数に対して、セクションという機能を使って部分適用をすることができる。
divideByTen :: (Floating a) => a -> a divideByTen = (/10) *Main> divideByTen 30 3.0
これは 30 / 10
と同義。
高階関数
関数を受け取り、2回適用する関数を書いてみる。先にScalaで書いてみよう。
def applyTwice[T](f: T => T)(x: T): T = f(f(x)) applyTwice { v: Int => v * 2 }(10) // 40
これを Haskell で書くとこうなる。
applyTwice :: (a -> a) -> a -> a applyTwice f x = f (f x) *Main> applyTwice (\a -> a * 2) 10 40
`(\a -> a * 2)` は Haskell の無名関数。
zipWith
標準ライブラリの zipWith
まずはHaskell標準の zipWith
の挙動を確認する。
*Main> :t zipWith zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith
は 2つの引数をとって1つの値を返す関数と、2つのリストを引数に取り、2つのリストの各要素に関数を適用することで、1つに結合する。
*Main> zipWith (\a b -> a + b) [1,2,3] [4,5,6] [5,7,9]
Scalaには zipWith
に相当するものはないが、zip
メソッドが collection
系には実装されている
List(1, 2, 3) zip List(2, 3, 4) // res2: List[(Int, Int)] = List((1,2), (2,3), (3,4))
2つのリストを引数にとって、前から順に同じ位置にある要素で構成されたタプルのリストを作って返す。これに map
を適用してあげれば、先程の haskell の zipWith
相当のことが可能だ。
List(1, 2, 3) zip List(2, 3, 4) map { case (a, b) => a + b } // res2: List[Int] = List(3, 5, 7)
zipWith
を実装してみる。※ 途中で、gist を使えば haskell もsyntax highlight いけることに気づいたので少し行数があるやつは試しに。
Scalaで同じようなことを書くとこんな感じ。最初の zip
と map
を連携させる方が読みやすいし書きやすい。
flip
普段Scalaを使っていて、さっきの zi
pWith なんかは似たようなもの、似たようなことを Scala でもやったことがあるが、これはhaskell本で初めてみる。
flip
は関数を引数にとり、引数が入れ替わった関数を返す。※正直、何が嬉しいのか全く分からない。
Main> :t flip flip :: (a -> b -> c) -> b -> a -> c
*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)]
zip
は1つ目の配列と2つ目の配列の同じ位置にある要素で作ったタプルのリストを返す関数だ。1つ目の通常の zip
では左の配列にあったものがタプルの左に、右の配列にあったものがタプルの右側にあるのが分かる。
flip
を適用した zip
はそれが逆になっている。:t
で見てみるとよく分かるが、引数が入れ替わっていることが分かる。
*Main> :t zip zip :: [a] -> [b] -> [(a, b)] *Main> :t flip zip flip zip :: [b] -> [a] -> [(a, b)]
自分で実装すると下記のようになる。