我感到困惑的是,编译器不会抱怨下面的代码(代码编译):为什么显然任何monad栈通常会派生MonadIO?
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Main where
import Control.Monad.IO.Class (MonadIO)
import Control.Monad.Except (ExceptT)
main = undefined
newtype Foo e m a = Foo { unFoo :: ExceptT e m a }
deriving (Functor, Applicative, Monad, MonadIO)
,将立即意义的,我再说一次,如果我不得不添加MonadIO m
为约束的地方,例如
deriving instance MonadIO m => MonadIO (Foo e m a)
而事实上,如果我尝试
deriving instance MonadIO (Foo e m a),
编译器会抱怨。
我也注意到,当我在那里添加约束MonadIO m
时,我只能使用liftIO
,不管我是否将方法二与独立派生和约束一起使用,这又是有道理的。在MonadIO m
的条件下的MonadIO
实例是。
这只是我,还是那种反直觉?
它是否与弃用的-XDatatypeContexts扩展有关?
我是知道的。但为什么这样做太笨拙了?例如。当我导出'MonadError e'时,我不必在稍后添加任何约束。 –
''MonadError e''不需要'm'的任何约束,因为使用'ExceptT'的实现,它适用于所有'm'。 'MonadIO'不能在没有'm'约束的情况下实现,因为它必须使用'm'中的实现,从而确保这种实现存在。它不是尴尬的,或者最不重要的就是它应该是尴尬的。 –
添加了文档链接并希望有更好的解释。 – Koterpillar