假设我在IO Int
中包含StateT MyState
,那么我想要在堆叠monad中使用State MyState Int
的值。如何在这种内在意义上解除它?我已经知道使用lift
或liftIO
如果我得到了与内部相容的内容,我只需要提升到外部monad,但现在我遇到了相反的问题:值已经在外面了monad但不是内在的。
例如:
checkSame :: State MyState a -> IO a -> StateT MyState IO Bool
checkSame sim real = do
rres <- liftIO real
sres <- ??? sim
return $ rres == sres
我必须得到&#39;状态,通过手动将其推送到runState并再次将其全部打开,或者是否有一些通用的方法来执行此操作?
顺便说一句,那个sim参数是一大堆与IO无关的有状态函数,所以如果我能避免它,我就不愿意让它们全部返回StateT MyState IO a
。
答案 0 :(得分:7)
您有两种选择:
让您的State
动作更具多态性。这是常用的,推荐的;它等于预先应用第1部分中的态射,但是在mtl
库中已经有很多机制可以使其变得容易。这里的想法是,如果您仅根据State
,get
和put
编写modify
操作,则代替类型State s a
,可以给它类型:
MonadState s m => m a
然后,在通话网站上,您可以选择适用于此的任何monad,包括State s a
和StateT s IO a
。此外,由于它专门针对State s a
类型,因此您可以确定它不会执行任何IO
或类似State s a
本身无法做到的事情,因此你得到了相同的行为保证。