2

我有一个执行一些 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

我试过使用liftIOfrom Control.Monad.IO.Class

-- C is the qualified import for Control.Monad.IO.Class
liftIO = C.liftIO

但这会导致NonTermination运行时异常:

uncaught exception: NonTermination (<<loop>>)

请问有什么办法可以解决这个问题吗?

4

1 回答 1

3

一种解决方案是支持 real IOin 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

于 2017-01-16T21:33:53.687 回答