Haskell 为什么任何单子堆栈都能派生出单子呢?
我很困惑编译器没有抱怨下面的代码(代码编译): 如果我必须在某个地方添加Haskell 为什么任何单子堆栈都能派生出单子呢?,haskell,io,monad-transformers,Haskell,Io,Monad Transformers,我很困惑编译器没有抱怨下面的代码(代码编译): 如果我必须在某个地方添加MonadIO m作为约束,例如 deriving instance MonadIO m => MonadIO (Foo e m a) 事实上,如果我尝试 deriving instance MonadIO (Foo e m a), 编译器抱怨 我还注意到,当我在那里添加约束MonadIO m时,我只能使用liftIO,而不管我是否使用了独立派生和约束的方法2,这也是有意义的。MonadIO实例处于MonadIO
MonadIO m
作为约束,例如
deriving instance MonadIO m => MonadIO (Foo e m a)
事实上,如果我尝试
deriving instance MonadIO (Foo e m a),
编译器抱怨
我还注意到,当我在那里添加约束MonadIO m
时,我只能使用liftIO
,而不管我是否使用了独立派生和约束的方法2,这也是有意义的。MonadIO
实例处于MonadIO m
的条件下
是只有我一个人,还是违反直觉
这与不推荐使用的-XDatatypeContexts扩展有关吗?对于
GeneralizedNewtypeDeriving
,所有实例都有相同的约束条件-newtype的基类型必须是同一类的实例:
实例所做的只是应用和删除newtype构造函数
的派生实例,即Monad
具有已存在的约束Monad(em除外)
。但是,MonadIO(m除外)
没有实例,因此它必须是对生成的MonadIO
声明的约束
如果我尝试使用MonadIO(Foo e m)
,将生成一个错误:
something :: Foo e m ()
something = liftIO $ print "5"
以下是错误:
• No instance for (MonadIO m) arising from a use of ‘liftIO’
Possible fix:
add (MonadIO m) to the context of
the type signature for:
something :: Foo e m ()
• In the expression: liftIO $ print "5"
In an equation for ‘something’: something = liftIO $ print "5"
我知道这一点。但为什么这样做会如此尴尬?例如,当我派生
MonadError E
时,我以后不必添加任何约束。MonadError E
不需要对m
进行任何约束,因为使用了ExceptT
的实现,这适用于所有m
MonadIO
在没有m
约束的情况下无法实现,因为它必须使用m
中的实现,从而确保存在这样的实现。这并不令人尴尬,或者至少它正是它所需要的尴尬。添加了一个链接到文档,希望有更好的解释。
• No instance for (MonadIO m) arising from a use of ‘liftIO’
Possible fix:
add (MonadIO m) to the context of
the type signature for:
something :: Foo e m ()
• In the expression: liftIO $ print "5"
In an equation for ‘something’: something = liftIO $ print "5"