如何结合两个不同的monad [英] How to combine two different monads
问题描述
我正在测试一台REST服务器。我在IO monad中找到它,并在 State Db
中模拟它,其中 Db
跟踪服务器的假定状态。下面的函数应该运行两个版本并比较结果...
check ::(Eq a,MonadState ds) => s a - > IO a - > s(IO Bool)
- 或者:check ::(等式a,MonadState d s,MonadIO i)=> s a - >我 - - > s(i Bool)
check _ _ =(return.return)False - 现在
<但是当我尝试使用这些最简单的功能时...
simReset :: State Db()
realReset :: IO()
reset :: StateT Db IO Bool
reset = check simReset realReset
我得到这个错误:
无法匹配预期类型`Bool'与实际类型`IO Bool'
预期类型:StateT Db IO Bool
实际类型:StateT Db IO(IO Bool)
在'check'调用的返回类型中
在表达式:检查simReset realReset
为什么?我该如何解决它?
(本主题从这里开始:提升以修复单元变压器堆栈的*内部*)
check
会返回一个 IO Bool
,而不管状态monad s
是。因此,当您传递 simReset
来检查状态Db
monad中的一次性操作时,返回值为将会是 State Db(IO Bool)
。 如何解决这个问题取决于你想要做什么做。基于你对 reset
的实现,你似乎试图与一个形式为 StateT Db IO a
。在这种情况下,您在 StateT Db IO
的上下文中描述了一种程序。有两种方法可以解决这个问题:
-
您可以升级
simReset
键入MonadState Db s => s()
(这实际上不需要任何实施变更)。 您可以定义一个提升它进入正确的monad
例如:
hoistState :: Monad m =>国家a - > StateT s m a
hoistState prg = StateT $ \st - >返回$ runState prg st
在任何情况下,您都可能想要保留重新执行并且结果在相同monad中:
check ::(等式a,MonadIO s,MonadState ds)=> s a - > IO a - > s Bool
然后,在解决方案一中,您有
reset = check simReset realReset
你有两个:
$ p $ reset = check(hoistState simReset)realReset
I'm testing a REST server. I hit it in the IO monad and simulate it in State Db
where Db
tracks the supposed state of the server. The following function is supposed to run both versions and compare the results...
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
but when I try it with these simplest possible functions ...
simReset :: State Db ()
realReset :: IO ()
reset :: StateT Db IO Bool
reset = check simReset realReset
I get this error:
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
Why? And how do I fix it?
(This topic started here: Lift to fix the *inside* of a monad transformer stack)
In your implementation, check
is going to return an IO Bool
regardless of what the state monad s
is. So, when you pass simReset
to check, which is a monadic action in the State Db
monad, the return value is going to be State Db (IO Bool)
.
How to fix it depends on what you're trying to do. Based on your implementation of reset
it seems like you're trying to interface with a transformer stack of the form StateT Db IO a
. In this case, you're describing a kind of program in the context of StateT Db IO
. There are two ways to go about this:
You can upgrade
simReset
to have typeMonadState Db s => s ()
(This shouldn't actually require any implementation change).You can define an auxiliary function that "hoists" it into the proper monad
For example:
hoistState :: Monad m => State s a -> StateT s m a
hoistState prg = StateT $ \st -> return $ runState prg st
In either case, you'll probably want to keep the action that you're performing and the result in the same monad:
check :: (Eq a, MonadIO s, MonadState d s) => s a -> IO a -> s Bool
Then, with solution one, you have
reset = check simReset realReset
And with solution two you have:
reset = check (hoistState simReset) realReset
这篇关于如何结合两个不同的monad的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!