3

假设我有一个IO Int包裹在 a 中StateT MyState,那么我有一个State MyState Int我想在堆叠的 monad 中使用的值。在这种内在的意义上,我如何举起它?我已经知道要使用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

我是否必须“获取”状态,手动将其推过 runState 并再次将其全部装箱,还是有一些通用的方法可以做到这一点?

顺便说一句,那个 sim 参数是一大堆与 IO 无关的有状态函数,所以StateT MyState IO a如果可以避免的话,我有点不愿意让它们全部返回。

4

1 回答 1

7

你有两个选择:

  1. 找到一个单子态射。这通常是找到合适的库的问题。在这种情况下,提升概括在一起应该可以让你到达你需要去的地方。
  2. 让你的State动作更加多态。这是常用的一种,也是推荐的一种;它相当于预先应用第 1 部分中的态射,但是库中已经安装了很多机器mtl以使其变得容易。这里的想法是,如果你只用 、 和 来编写你的动作,State那么你可以给它类型而不是type :getputmodifyState s a

    MonadState s m => m a
    

    稍后,在调用站点,您可以选择任何适合于此的 monad,包括State s aStateT s IO a。此外,由于它专门用于 type State s a,因此您可以确定它不会做任何IO自己State s a无法做的事情,因此您可以获得相同的行为保证。

于 2014-11-29T19:30:00.857 回答