Haskellの関数合成
$と.と()について
例として関数fとgの型をそれぞれ以下のように定義して話を進める
f :: b -> c
g :: a -> b
($) :: (a -> b) -> a -> b
右に伸びるカッコの省略できるということが嬉しくて使ってるmrsekut.icon
右結合性を持つ
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"とする必要がある
並べて書くと違いがほとんどないことに気付く
登場人物の関数たちが1引数関数というところが$のときと違って意識するところ
なので途中に2引数関数がある場合は良い感じに1引数関数にしてやる必要がある
code:hs
foo p xs = sum $ filter p $ map (+1) xs -- $を使ったとき
foo p = sum . filter p . map (+1) -- .を使ったとき
$はイメージ的には()の省略と同じ
何回か関数を実行してる感じ
code:hs
foo p xs = sum (filter p (map (+1) xs))
.はでかい関数を作った後に一発実行してる感じ
code:hs
foo p xs = (でかい一つの関数) xs
.で多引数関数にも対応する
ドットをいっぱい書けばいいらしい
h = (f.).g
.に、2引数関数と1引数関数を与えると、2引数関数ができる
code: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引数関数
code: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という順番は変わらずに、あいだの演算子だけが変わってる
次に、「いくつか選択できる場合にどれを使うか?」という問題が生じる
つまり.を使っていく
選べる場合は左から右に読めるようにする、とか
以下5つは全て同じ挙動になる
code: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.iconが遭遇したのは以下のような状況
code:purs(hs)
printStr (HashMap ms) = "{" <> (ms # toUnfoldable # flatTuples # printList) <> "}"
だからポイントフリースタイルは採用できない(したとてキモくなるので)
だから4つともほぼ平等に選択の余地がある
参考
初心者は()が多く、中級者で$を使い、上級者は.を使う
一段階目では、一番右側の括弧を消して、その始まりを$に変える
つまり、一番右側には括弧は存在しなくなる
中間には存在し得る