letのところは無視してdo構文の各行を最終的な型だけで見てやったら それぞれこんな感じになって、 1. do {r <- IO r; IO ()} 2. do {r <- IO r; String} 3. do {r <- IO r; [Int]}
これを >>= を使った形にしたらこんな感じ。 1. IO r >>= (r -> IO ()) 2. IO r >>= (r -> String) 3. IO r >>= (r -> [Int])
(>>=) :: m a -> (a -> m b) -> m bだから >>=の前後は m a >>= (a -> m b) って状態になってないといけない。 1はちゃんとそれを満たしてるからOKだけど、 2はString = [Char] = [] Charで、IO ≠ []なのでNG。 3も同様にNG。