モナドとしての(->)がなぜReaderモナドなのか理解した


# (->)をMonadとして使ってみる

`((->) r)`型構築子はモナドでもあるということなので、しつこいが関連する函数の型を思い出しておく。型図式の`m`が`(r->)`になることを思い出して：

```hs:
(<$>) :: (a->b)  ->  (r->a) -> (r->b)
pure :: (a->b) -> (r->a->b)
(<*>) :: (r->a->b)  ->  (r->a) -> (r->b)
```

さて、モナドは`return`と`>>=`を持っていなければならない。`return`はアプリカティヴの`pure`と同じなのでそれでいい。`>>=`の型を確認すると：

```hs:
(>>=) :: m a -> (a -> m b) -> m b
(>>=) :: (r->a) -> (a -> (r->b)) -> (r->b)
```

なんのことやらさっぱりである。(->)モナドでの`>>=`の定義によれば：

```hs:
(>>=) f g = \x -> g ( f x ) x
```

であるようだ。`h`はr->a型の函数、`f`はa->r->b型の函数である。ということは`x`はr型の値でなくてはいけない。`(f x)`の部分はa型なので`g (f x) x`はb型、つまり、このラムダ式はr型の値を取ってb型の値を返してくる(r->b)型の函数だ。だから型はこれで合っている。で、これってどう振る舞うんだろう。やっぱりわからん。

モナドにするには>>=ではなくjoin :: m (m a) -> m aというようにモナドの入れ子を外す函数`join`を定義するのでもいいらしい。joinの定義は：

```hs:
join f = f >>= id
join f = \x -> id (f x) x = \x-> f x x
```
引数を2つに増殖させて`f`に引き渡す函数か。f は二重にモナドに入った値、つまり型の頭にr->r->がついているような函数r->r->?を取って、型rの引数を増殖させることでr->?に潰すわけか。これはわかりやすい。`join (+) 5 = (+) 5 5 = 10`になるわけね。逆に`(>>=)`がjoinから定義できて：

```hs:
f >>= g =  join ((fmap g) f)
```
だという。確認してみると`\x -> ((fmap g) f) x x` = `\x -> g.f x x` = `\x -> g (f x) x`でなるほど定義通りである。同じことだが、`join`と`(>>=)`の関係は`(>>=)`の引数を逆にした`(=<<)`を考えればわかりやすい。

```hs:
(=<<) :: a-> m b -> m a -> m b
(=<<) :: (a ->(r->b)) -> (r->a) -> (r->b)
```
普通の`fmap`の型は(a->b) -> m a -> m bだから、`f=<<g`の代わりに`f<$>g`とするとその結果の型はm (m b)になる。だから、これを`join`で外してやればいい。つまり、`f=<<g`=`join(f<$>g)`だ。`join`はまあわかるけど、それでもやっぱり`(>>=)`が直観的に理解できない。うーん。後の函数を前の対象に`fmap`してモナドを１段階潰した・外したもの（ということは函数合成をしてその結果の頭の(r->r->)部分に同じr型の値を供給することによって(r->)に潰したもの）と考えればいいんだけど……

# do構文

しょうがないのでdo構文から遡って考えるか。`(^)<$>(*3)<*>(+2)`という函数を考えよう。アプリカティヴとしての使い方はわかってるから、これは`n :: Integer`を取って`(n*3)^(n+2)`を返す函数だ。これを函数`expo`としよう。そうすると実はdo記法を使って

```hs:
expo = do
    a <- (*3)
    b <- (+2)
    return (a^b)
```

と書ける。つまり`f<$>g<*>h`は

```hs:
func = do
    a <- g
    b <- h
    return (f a b)
```

と書ける。構文糖衣を剥がしてやると：

```hs:
func = g >>= (\a -> h >>= (\b -> return (f a b)))
```
だ。だいぶ見えてきた気がする。一番単純な`f<$>g`を考えよう。

```hs:
func = g >>= (\a -> return (f a))
```

なるほどなるほど。` func  = \x -> (\a -> return (f a)) (g x) x` = `\x-> return (f (g x)) x`で最後の`x`が`return`によって――`f (g x)`の引数を形式的にひとつ追加してそこにこの最後の`x`を受けつつ無視して捨てることによって――読み捨てられ`\x->(f (g x))`つまり`f.g`が残るという仕組みなんだな。

```hs:
func = g >>= (\a -> h >>= (\b -> return (f a b))) -- 次に>>=を展開
= \x -> ( (\a -> h >>= (\b -> return (f a b)))  (g x) x) -- 次に(g x)が\aに入る
= \x -> ( (h  >>=  (\b -> return (f (g x) b)))  x) -- 次に>>=を展開
= \x -> ( (\y ->  (\b -> return (f (g x) b)) (h y)  y)   x) -- 次にxが\yに入る
= \x -> ( (\b -> return (f (g x) b))  (h x)  x) -- 次に(h x)が\bに入る
= \x -> ( (return ( f (g x) (h x))  x) -- 最後のxはreturnによって捨てられる
= \x -> f (g x) (h x)
```

`f >>=g = \ x -> g (f x) x` の中の`(f x)`の部分が連鎖中のラムダ式の適用を受けてラムダ式の中に入っていくことで全体が縮んでいくわけだ。末尾の`x`の部分は`(>>=)`を展開した時のラムダ式に適用されて中に入っていく（入った先でも末尾にあるので同じように残る）。この過程を経る間、末尾の`x`が残り続けるが、これを最後に`return`で読み捨てて綺麗にする、と。do構文だと、`g`と`h`と`return(...)`の総てに`func`に与えられた引数が分配供給されるところ、`return`の中身`（...）`は`func`の引数を利用しないので（しかし放っておいてもそれを勝手に分配されるので）`return`でくるんで`func`の引数を引き受ける場所を形式的に作って読み捨ててるわけだ。`func`の引数になってる型の値を（いらなくても）配給される、というのがこのモナドの「文脈」ということなんだな。

`>>=`の意味を言葉ではうまく説明できないが、少なくとも仕組みは理解できた気がする。

```hs:
func = g >>= (\a -> h >>= (\b -> return (f a b)))
```

について、この函数が`x`に適用された場合、最初の`g`がそれに適用された時の値`(g x)`が`>>=`の後のラムダ式に入り、次の`h`が`x`に適用された時の値`(h x)`が`>>=`の後のラムダ式に入り、と計算が進んでいく、というわけだ。とりあえず納得はした。

# ようやく理解した

もういちど`(>>=)`の型を確認してみよう。`(>>=)`は左側の函数の頭のa->を剥ぎ取り、右側の高階函数に引き渡し、この高階函数はその引数を取って頭にr->がついた型の函数を返してくる。これはつまり、左側の函数にa型の引数が添えられたものと考えて計算を進めて、最後にその引数をラムダ抽象した結果を返す、という理解でいいのだろう。ポイントは、`(>>=)`連鎖の間に現れてくる函数のどれについても添えられたものと仮定される引数は「同じ」値だってことだ。

```hs:
func = g >>= (\a -> h >>= (\b -> return (f a b)))
```

`g`に、引数`x`が添えられたものと考えよう。そうすると、`(>>=)`によって`(g x)`が右側のラムダ無名函数の引数になる。てことは函数適用してやって：

```hs:
h >>= (\b -> return (f (g x) b))
```

次に`h`にも同様のことをするのだが、`h`に添えられたものと考える引数は新たな`y`とかではなくさっきの`g`と同じ`x`なんだ。これこそが(r->)モナドの意味なんだな。`(>>=)`によって`(h x)`が右側のラムダ無名関数の引数になる。てことは関数適用してやって：

```hs:
return (f (g x) (h x))
```

連鎖の最後までどの函数にも`x`が添えられたものと考えるから、`return (f (g x) (h x)) x`になって`return`は`x`を無視する定数函数を返してくる。だから結果は

```hs:
f (g x) (h x)
```

だ。で、これをさっきから添えてきた`x`についてラムダ抽象してやれば：

```hs:
\x -> f (g x) (h x)
```

だ。これでスッキリ理解できた。モナドの連鎖中ずっと「同じ」引数が適用され続けるものと考えて計算を進めて最後にラムダ抽象で全体を(r->)モナドに戻せばいいということなんだな。このモナドがReaderモナドでもある理由もやっとはっきりと理解できた。連鎖中の函数すべてに「環境」として理解されたr型の「同じ」値を不変的に渡し続けて計算を進めるわけだ。最後にラムダ抽象でr->型の函数に戻して、任意の「環境」を引数に取る、ひとつにまとめあげられた函数を作り上げるわけ。やっと理解した。この文脈での`join`の意味も明瞭になった。函数合成の結果r->r->が頭についたモナドの連鎖に対して、そのr->r->部分に同じr型の値を二度供給してr->に項数を減らすわけ。これが問題なくできるのは、まさに「同じ」引数を供給して計算を進めていく、という(r->)モナドの基本的文脈のおかげ。わかってみれば、まさにApplicative Styleでやってたことそのままだ。

めでたしめでたし。