我正在测试 REST 服务器。我在 IO monad 中击中它并在中模拟它State Db
where Db
跟踪服务器的假定状态。以下函数应该运行两个版本并比较结果......
check :: (Eq a, MonadState d s) => s a -> IO a -> s (IO Bool)
-- or: check :: (Eq a, MonadState d s, MonadIO i) => s a -> i a -> s (i Bool)
check _ _ = (return.return) False -- for now
但是当我尝试使用这些最简单的功能时......
simReset :: State Db ()
realReset :: IO ()
reset :: StateT Db IO Bool
reset = check simReset realReset
我收到此错误:
Couldn't match expected type `Bool' with actual type `IO Bool'
Expected type: StateT Db IO Bool
Actual type: StateT Db IO (IO Bool)
In the return type of a call of `check'
In the expression: check simReset realReset
为什么?我该如何解决它?
(这个话题是从这里开始的:提升以固定单子变压器堆栈的“内部” https://stackoverflow.com/questions/27200132/lift-to-fix-the-inside-of-a-monad-transformer-stack)
在您的实施中,check
将返回一个IO Bool
不管状态单子是什么s
是。所以,当你通过simReset
检查,这是一个单子动作State Db
monad,返回值将是State Db (IO Bool)
.
如何解决它取决于您想要做什么。根据您的实施reset
看来您正在尝试与以下形式的变压器堆栈进行交互StateT Db IO a
。在本例中,您在以下上下文中描述一种程序:StateT Db IO
。有两种方法可以解决这个问题:
您可以升级simReset
有类型MonadState Db s => s ()
(这实际上不需要任何实现更改)。
您可以定义一个辅助函数,将其“提升”到正确的 monad 中
例如:
hoistState :: Monad m => State s a -> StateT s m a
hoistState prg = StateT $ \st -> return $ runState prg st
无论哪种情况,您可能都希望将正在执行的操作和结果保留在同一个 monad 中:
check :: (Eq a, MonadIO s, MonadState d s) => s a -> IO a -> s Bool
然后,通过解决方案一,您可以得到
reset = check simReset realReset
通过解决方案二,您可以得到:
reset = check (hoistState simReset) realReset
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)