Каждый оператор в блоке do
должен относиться к одному и тому же монадическому типу.
В
multWithLog = do
a <- logNumber 3
return a
у нас есть logNumber 3 :: Writer [String] Int
и return a :: (Monad m) => m Int
(что является полиморфным), поэтому все типы проверяются как Writer [String] Int
(с m = Writer [String]
, который является монадой).
В
main = do
putStrLn $ show $ logNumber 3
putStrLn $ show $ multWithLog
_ <- logNumber 3
putStrLn "test"
у нас есть putStrLn ... :: IO ()
и logNumber 3 :: Writer [String] Int
. Это ошибка типа, потому что Writer [String]
отличается от IO
.
Основная причина в том, что блоки do
являются просто синтаксическим сахаром для вызовов >>=
и >>
. Например. ваш main
действительно означает
main =
(putStrLn $ show $ logNumber 3) >>
(putStrLn $ show $ multWithLog) >>
logNumber 3 >>= \_ ->
putStrLn "test"
с
(>>) :: (Monad m) => m a -> m b -> m b
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
, который требует, чтобы тип m
оставался неизменным.