haskell-jp / questions #99 at 2021-11-24 15:18:45 +0900

質問失礼します.
f(g(x)) はf.g $ x と表されますが,関数を連ねてしてデータを変換するという思考プロセスであれば,g.fのほうが自然かと思います.シンボルを読むのは左から右なのに,関数適用の順序を追って行くのは右から左に読むのは不自然です.UXINコマンドのパイプの思考に侵され過ぎているだけでしょうか?
ただ,この仕様を変更しただけでは,今度は前置記法から来る違和感が発生するとは思います.

既出の議論であれば申し訳ございません.
数学の関数合成にならったんだと思います
https://ja.wikipedia.org/wiki/%E5%86%99%E5%83%8F%E3%81%AE%E5%90%88%E6%88%90
ちなみに (Data.Function.&) を使えば
f $ g x -- を
x & g & f -- と書けます
そのような関数が定義されていたのですね、ありがとうございます!
さらにHaskellに好感が持てました。

ただ、Data.Fuction.&を使うとフリーポインタスタイルで仮引数を消すのはできなくなってしまいますよね:smiling_face_with_tear:
関数合成については、Control.Categoryに f >>> g = g . f というのがありますね https://hackage.haskell.org/package/base-4.16.0.0/docs/Control-Category.html#v:-62--62--62-
どのように、考えるか、見るかによって、自然な書き方が違ってくるのだと思います。
関数を連ねてしてデータを変換するという思考プロセス
では、ボトムアップで考えているので、おっしゃる通り g、f という順序が自然にみえます。
逆にトップダウンで考えているのなら、 f、g という順序が自然に見えるでしょう。
たとえば、リストの構成は通常トップダウンでみていますから、[1,2,3]を構成するとき、h = (1:) . (2:) . (3:) として h $ [] とするほうが h = (3:)
(2:)
(1:) として [] & h とするよりも自然に見えます。
OCamlで |> という演算子が流行っているようですが、Haskellでも簡単に実装できます。

> (f |> g) x = g (f x)
> :type (|>)
(|>) :: (t1 -> t2) -> (t2 -> t3) -> t1 -> t3
> (map (+1) |> sum) [1,2,3]
9