将具有monad参数的函数提升到monad变换器中

时间:2015-08-21 15:27:53

标签: haskell monad-transformers

我想解除像mask_ :: IO a -> IO a这样的函数来创建一个带有此签名的函数:lmask_ :: StateT Bool IO a -> StateT IO a

我的问题是,如何处理回调/第一个参数?以下代码是否不正确,因为它会在mask_代码之前执行回调?

lmask_ :: StateT Bool IO a -> StateT Bool IO a
lmask_ m = do
  r <- m
  lift (mask_ (return r))

有一些通用的方法吗?像lift1 :: MonadTrans t => (m a -> m a) -> (t m a -> t m a)这样的帮手?

2 个答案:

答案 0 :(得分:2)

一般来说,如果不了解有关monad变压器的信息,这是不可能的。但是,对于所有标准monad变换器,有一种方法可以做到这一点。请参阅类型类MonadBaseControl。它的超类MonadBase定义了monad变换器堆栈中的底部monad(对于包含IO的所有堆栈,IO),MonadBaseControl定义了如何将monad嵌入基地monad。它的实例有些复杂,但一旦定义了它们,就可以解除所有这些函数,如mask_

在您的情况下,包提升基础使用上述结构重新定义提升到IO的标准MonadBaseControl函数。特别是mask_

mask_ :: MonadBaseControl IO m => m a -> m a

可以专门用于StateT Bool IO a -> StateT Bool IO a,因为StateT s的实例为MonadBaseControl

另见Lift a function and its argument to a different monadic context

答案 1 :(得分:1)

如果我们推广lmask_以摆脱StateT Bool IO,我们会得到类似的结果:

lift1 :: (Monad m, Monad (t m), MonadTrans t) => (m a -> m a) -> (t m a -> t m a)
lift1 f term = do
    x <- term
    lift (f (return x))