Reader モナド(関数モナド)

すごい Haskell たのしく学ぼう!の14.2章331ページの関数モナドを do 記法で書いてあるコード、どういう動作になるかは解説されてあるので分かるのだけどなんでそうなるのかが分からないので書き下してみる。
くだんのコードは下記。

import Control.Monad.Instances

addStuff :: Int -> Int
addStuff = do
    a <- (*2)
    b <- (+10)
    return (a + b)

これを下記のインスタンス宣言に則って書き下していく。

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

以下は厳密な Haskell コードじゃない。

do
    a <- (*2)
    b <- (+10)
    return (a + b) =
(*2) >>= \a -> (+10) >>= \b -> return (a+b) =                        -- do 記法シンタックスシュガーを外す
\w -> (\a -> (+10) >>= \b -> return (a+b)) ((*2) w) w =              -- 1つめの >>= を展開
\w -> (\a -> \w' -> (\b -> return (a+b)) ((+10) w') w') ((*2) w) w = -- もう1つめの >>= を展開
\w -> \w' -> (\b -> return (((*2) w)+b)) ((+10) w') w' w =           -- \a -> ... に ((*2) w) を適用
\w -> \w' -> return (((*2) w) + ((+10) w')) w' w =                   -- \b -> ... に ((+10) w') を適用
\w -> \w' -> \_ -> (((*2) w) + ((+10) w')) w' w =                    -- return を展開
\w -> \w' -> (((*2) w) + ((+10) w')) w =                             -- \_ -> ... に w' を適用
\w -> ((*2) w) + ((+10) w) =                                         -- \w' -> ... に w を適用
\w -> w*2 + (w+10)                                                   -- 中置記法に

ちゃんと展開できたー。展開の順序が合ってるかは知らないけど。
こんなちゃんと展開しなくても関数モナドの意味だけなら次のようなイメージでなんとかなる。イメージとしては、引数の値を各行に対して、分配の法則を用いる。

addStuff = do
    a <- (*2)
    b <- (+10)
    return (a + b)
addStuff' x = let
    a = (*2) x
    b = (+10) x
    in a + b

てことを昨日の帰り考えてた。