generated at
Haskellの関数合成
$ . () について
例として関数 f g の型をそれぞれ以下のように定義して話を進める
f :: b -> c
g :: a -> b

($) :: (a -> b) -> a -> b
右に伸びるカッコの省略できるということが嬉しくて使ってるmrsekut
右結合性を持つ
f $ g $ r == f (g r)
ちなみに、普通の関数適用は左結合である
f g r == (f g) r
関数の適用演算は結合律を満たさない
(f g) r != f (g r)
$ の優先順位は二項演算子の中で最低


(.) :: (b -> c) -> (a -> b) -> a -> c
例えば f . g なら
f :: b -> c g :: a -> b なので
式全体で見れば f . g :: a -> c を表す
右結合性を持つ
f . g . r == f . (g . r)
結合律を満たす
(f . g) . r == f . (g . r)
. の優先順位は二項演算子の中で最高
ただし、関数適用よりは低い
print . show "42" はエラーになる
print . (show "42") と解釈されている
(print . show) "42" とする必要がある


. $ と適用の順番は同じ ref
並べて書くと違いがほとんどないことに気付く
登場人物の関数たちが1引数関数というところが $ のときと違って意識するところ
なので途中に2引数関数がある場合は良い感じに1引数関数にしてやる必要がある
hs
foo p xs = sum $ filter p $ map (+1) xs -- `$`を使ったとき foo p = sum . filter p . map (+1) -- `.`を使ったとき
$ はイメージ的には () の省略と同じ
何回か関数を実行してる感じ
hs
foo p xs = sum (filter p (map (+1) xs))
. はでかい関数を作った後に一発実行してる感じ
hs
foo p xs = (でかい一つの関数) xs


. で多引数関数にも対応する
ドットをいっぱい書けばいいらしい
h = (f.).g


. に、2引数関数と1引数関数を与えると、2引数関数ができる
hs
(.) :: (b -> c) -> (a -> b) -> a -> c mappend :: Monoid a1 => a1 -> a1 -> a1 -- 2引数関数 f :: a -> a1 -- 1引数関数 (.) mappend :: Monoid a1 => (a -> a1) -> a -> a1 -> a1 (.) mappend f :: Monoid a1 => a -> a1 -> a1 -- 2引数関数


pipeline operatorを導入する
hs
(|>) :: a -> (a -> b) -> b a |> f = f a
書く順序と流れが一致する
pursには # という関数がある


書き換えをしてみよう
(f . g) x は、以下全てと同値
f (g x)
(f . g) $ x
f $ ( g $ x)
f . g $ x
f $ g $ x
f , g , x という順番は変わらずに、あいだの演算子だけが変わってる



次に、「いくつか選択できる場合にどれを使うか?」という問題が生じる
point-free styleで書ける場合はそうする、とか
つまり . を使っていく
選べる場合は左から右に読めるようにする、とか
以下5つは全て同じ挙動になる
purs(hs)
printStr ms = printList (flatTuples (toUnfoldable ms))) printStr ms = ms # toUnfoldable # flatTuples # printList printStr ms = printList $ flatTuples $ toUnfoldable ms printStr = printList <<< flatTuples <<< toUnfoldable printStr = toUnfoldable >>> flatTuples >>> printList
このケースでは、 () は個人的には論外としたい
# >>> なら、左から右に読める
しかしHaskellerやpursマンは、右から左に読むことを特に苦と思っていないはず
むしろソッチの方が慣れている
だから、左から右に読めたとて、ふーんぐらいでしかない
>>> <<< なら、ポイントフリーに書ける
実際にmrsekutが遭遇したのは以下のような状況
purs(hs)
printStr (HashMap ms) = "{" <> (ms # toUnfoldable # flatTuples # printList) <> "}"
だからポイントフリースタイルは採用できない(したとてキモくなるので)
だから4つともほぼ平等に選択の余地がある




参考
初心者は () が多く、中級者で $ を使い、上級者は . を使う
一段階目では、一番右側の括弧を消して、その始まりを $ に変える
つまり、一番右側には括弧は存在しなくなる
中間には存在し得る