fugafuga.write

日々のログ

すごいH本 part24

メリークリスマス 🎅

チキン食いました

関数合成

.関数を使う。

他の関数に渡す関数をその場で作るときに使う。ラムダ式でできるが、関数合成のほうが簡潔に書けるらしい。

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

関数を2つ引数にとって引数を1つとる関数を返す。

例として数のリストの全部を負のリストにする。

ラムダ式

*Main> map (\x -> negate (abs x)) [4,-2,5,1,-7]
[-4,-2,-5,-1,-7]

関数合成

*Main> map (negate . abs) [4,-2,5,1,-7]
[-4,-2,-5,-1,-7]

関数合成は右結合なので複数の関数を合成できる

*Main> map (\xs -> negate (sum (tail xs))) [[1..5],[3..6],[1..7]]
[-14,-15,-27]

関数合成で書く

*Main> map (negate . sum . tail) [[1..5],[3..6],[1..7]]
[-14,-15,-27]

リストの要素に tail, sum, negate の順で適用していく。 関数適用で書くと tail に引数が必要になる。

他引数関数の関数合成

複数の引数を取る関数を合成する場合、部分適用して引数を1つとる関数を作る。

*Main> sum (replicate 5 (max 6.7 8.9))
44.5

この式は次のように書き換えられる

*Main> (sum . replicate 5) (max 6.7 8.9)
44.5

次のように書いてもよい

*Main> sum . replicate 5 $ max 6.7 8.9
44.5

この場合、replicate に 5 を渡して部分適用させている。

*Main> :t replicate
replicate :: Int -> a -> [a]

*Main> :t replicate 5
replicate 5 :: a -> [a]

括弧だらけの式を関数合成を使って書き直す場合、まず

  1. 一番内側の関数とその引数を書き出す
  2. 書き出したものの前に$を置く
  3. その前に置かれていた関数から最後の引数を除去
  4. 間に.を置いて合成する
*Main> replicate 2 (product (map (*3) (zipWith max [1,2] [4,5])))
[180,180]

関数合成

*Main> replicate 2 . product . map (*3) $ zipWith max [1,2] [4,5]
[180,180]

所感

複数関数合成されている場合、右から読んでいくのが慣れなくてつらい。練習しないと定着しなさそうである。

Haskell の関数合成 | すぐに忘れる脳みそのためのメモ

この記事はとてもわかりやすかった。

そんでもってカリー化と部分適用の素晴らしさを改めて感じた。

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

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

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