抬起以固定monad变压器堆栈的* inside *

时间:2014-11-29 07:51:40

标签: haskell monad-transformers lifting

假设我在IO Int中包含StateT MyState,那么我想要在堆叠monad中使用State MyState Int的值。如何在这种内在意义上解除它?我已经知道使用liftliftIO如果我得到了与内部相容的内容,我只需要提升到外部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

1 个答案:

答案 0 :(得分:7)

您有两种选择:

  1. 找一个monad态射。这通常是找到合适的图书馆的问题;在这种情况下,hoistgeneralize可以让您到达目的地。
  2. 让您的State动作更具多态性。这是常用的,推荐的;它等于预先应用第1部分中的态射,但是在mtl库中已经有很多机制可以使其变得容易。这里的想法是,如果您仅根据Stategetput编写modify操作,则代替类型State s a,可以给它类型:

    MonadState s m => m a
    

    然后,在通话网站上,您可以选择适用于此的任何monad,包括State s aStateT s IO a。此外,由于它专门针对State s a类型,因此您可以确定它不会执行任何IO或类似State s a本身无法做到的事情,因此你得到了相同的行为保证。