我有一个执行某些IO的类型类。我使用MonadIO
:
class MonadIO m => MonadDB m where
getSomething :: String -> m Something
getSomething s = -- do some IO stuff with liftIO
在测试中,我希望替换实现,以便我可以测试使用getSomething
的函数,所以我这样做:
newtype WorkingDBM a = WorkingDBM (Identity a)
deriving (Functor, Applicative, Monad)
instance MonadDB WorkingDBM where
getSomething s = return $ Something "blah"
没有实例声明,代码会发出警告:
• No explicit implementation for ‘liftIO’
• In the instance declaration for ‘MonadIO WorkingDBM’
所以我补充说:
instance MonadIO WorkingDBM
当然会编译。
在Hspec中运行测试会导致此运行时错误:
uncaught exception: NoMethodError (test/BlahSpec.hs:45:10-33: No instance nor default method for class operation liftIO
我尝试使用liftIO
中的Control.Monad.IO.Class
:
-- C is the qualified import for Control.Monad.IO.Class
liftIO = C.liftIO
但这会导致NonTermination
运行时异常:
uncaught exception: NonTermination (<<loop>>)
我有什么想法可以解决这个问题吗?
答案 0 :(得分:2)
一种解决方案是支持IO
中的真实WorkingDBM
。例如:
newtype WorkingDBM a = WorkingDBM (IO a) -- N.B. IO not Identity
deriving (Functor, Applicative, Monad)
instance MonadIO WorkingDBM where
liftIO = WorkingDBM
MonadIO
的派生实例也可以正常工作;但是空实例不会,因为它等同于
instance MonadIO WorkingDBM where
liftIO = undefined
这会在您第一次尝试IO
时显然会爆炸。