haskell-jp / beginners #25 at 2024-07-20 22:40:21 +0900

関数モナドについて調べてみたのですが、理解できなかったので質問させてください。

instance Monad ((->) r) where
    return = const
    h >>= f = \w -> f (h w) w

これを使用したときに以下のようになると思います。
ghci> f = (+1) >>= \a -> (+2) >>= \b -> return (a+b)
f :: Num b => b -> b
ghci> f 1
5
it :: Num b => b

上記の場合 h w(+1) 1 に置き換えられると考えています。
同様に、`f (h w) w` を単純に置き換えると (+2) ((+1) 1) 1 になってしまいますが
おかしいのは理解できています。

これはどのように考えたらよいのでしょうか ?
どう展開したら正しくなるかまだ私自身分かってないですが、 f の定義のうち後半の >>= \b -> return (a+b) の部分を展開していないので f はそのように置き換えられないと思います。
ああー、そうか。 f って識別子が二つあるから私が質問の意図を誤解してるかも。答えになってなかったらごめんなさい。
@igrep
ありがとうございます。

はい。Reader モナドであれば (h w) を引数に f から (+2) を取り出してそれが引数に適用されると素直に考えられるのですが、この場合はうまく適用して考えられませんでした。
(GHCiでの定義の)`f`には2つのバインド (`>>=`) があります。
まず左のバインドで定義を使って置き換えると、`h`は (+ 1) に、(バインドの定義の)`f`は仮引数`a`を取るラムダ式です。
いま`1`に(GHCiでの定義の)`f`を適用しているため、たしかに`h w`は`(+ 1) 1`に置き換わります。

「同様に」のところを考えます。
ここまでで`f 1`は
   (\a -> (+ 2) >>= \b -> return (a + b)) ((+ 1) 1) 1
--  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

で、波線部分が(バインドの定義の)`f`だったところです。
これはセクション (+ 2) にはならないため、2つ目の置き換えがまずそうです。

計算過程: https://pastebin.com/vrDiUVkM
@gemmaro
計算過程も作成していただき、理解しやすいです。

2 つ目につながるところまで考慮しなければならないのですね。
頂いた pastebin の図をもとに、理解できるように再度トライしてみます。

丁寧な解説をありがとうございました。