我很困惑,编译器不会抱怨下面的代码(代码编译):
{-# 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),
编译器抱怨。
我还注意到,当我在那里添加约束liftIO
时,我只能使用MonadIO m
,无论我是否使用方法二和独立的派生和约束,这又是一种说得通。 MonadIO
实例在<{1}} 的条件下。
只是我,还是反直觉?
是否与弃用的-XDatatypeContexts扩展名有关?
答案 0 :(得分:1)
使用GeneralizedNewtypeDeriving
,所有实例都具有相同的约束 - newtype
的基本类型必须是同一类的实例:
Generalised derived instances for newtypes
所有实例都应用并删除newtype构造函数。
派生实例,即Monad
具有已存在的约束Monad (ExceptT e m)
。但是,MonadIO (ExceptT e 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"