为什么显然任何 monad 堆栈通常都可以派生 MonadIO?
Why can apparently any monad stack generally derive 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
实例 在 MonadIO m
的条件 下。
这只是我,还是违反直觉?
是否与已弃用的 -XDatatypeContexts 扩展有关?
对于 GeneralizedNewtypeDeriving
,所有实例都具有相同的约束 - newtype
的基类型必须是相同 class:
的实例
Generalised derived instances for newtypes
All the instance does is apply and remove the newtype constructor.
的派生实例,即 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"
我很困惑编译器没有抱怨下面的代码(代码编译):
{-# 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
实例 在 MonadIO m
的条件 下。
这只是我,还是违反直觉?
是否与已弃用的 -XDatatypeContexts 扩展有关?
对于 GeneralizedNewtypeDeriving
,所有实例都具有相同的约束 - newtype
的基类型必须是相同 class:
Generalised derived instances for newtypes
All the instance does is apply and remove the newtype constructor.
的派生实例,即 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"