为什么可以替换这些类型?

Why it it possible to replace these types?

有些事情似乎很不可思议:

foo :: a -> StateT Env (ReaderT Env (ErrorT String IO)) String

可以替换为
foo :: a -> ErrorT String IO String

怎么可能?毕竟是完全不同的类型...

显然,在所有 情况下不可能将它们相互替换。例如,如果您明确使用 ErrorT . return $ Left "Muahar",则此 必须 ErrorT String m a.

但是,这两种类型都是 a -> M String 形式,带有一个 (transformer-stack) monad M,它是 MonadIO and MonadError String 的一个实例。因此,如果仅使用 liftIO ioaction 形式的操作定义此函数,并且可能使用 throwErrorcatchError 形式的操作,那么它将像这些 monad 中的任何一个一样工作。一般类型是

foo :: (MonadIO m, MonadError String m) => a -> m String