如果其中一个monad被包裹在monad变换器中,是否可以重用monad合成函数?

chi*_*ro2 2 monads haskell monad-transformers

假设我有函数组成两个monad动作:

co :: Monad m => m a -> m a -> m a

您可以将其co视为更高阶函数,描述两个monadic动作如何相互合作以完成任务.

但现在我发现第一个monadic动作可能包含在monad变换器中,而第二个不是:

one :: (MonadTrans t, Monad m) => t m a

two :: Monad m => m a

但是还是想把它们组合在一起,所以我需要一个功能:

co' :: (MonadTrans t, Monad m) => t m a -> m a -> t m a

因此,第一个t m a可以m a通过将所有m原语提升到上下文中来合作t.

这里的诀窍是在co不知道mor 的实现的情况下构建t.我觉得答案是在MFunctor包中的某个地方,事实上昨天也提出了类似的问题.但是想不出什么好的,有什么想法吗?

Gab*_*lez 5

您可以hoistmmorph包中使用. hoist允许你修改实现的任何东西的基本monad MFunctor(大多数monad变换器):

hoist :: (MFunctor t) => (forall x . m x -> n x) -> t m r -> t n r
Run Code Online (Sandbox Code Playgroud)

然后你可以用它来解决你的问题:

co' tma ma = hoist (co ma) tma
Run Code Online (Sandbox Code Playgroud)

那你就完成了!

为了理解其工作原理,让我们一步一步地查看类型:

co :: (Monad m) => m a -> m a -> m a

ma :: (Monad m) => m a

co ma :: (Monad m) => m a -> m a

hoist (co ma) :: (Monad m, MFunctor t) => t m a -> t m a

tma :: (Monad m, MFunctor t) => t m a

hoist (co ma) tma :: (Monad m, MFunctor t) => t m a
Run Code Online (Sandbox Code Playgroud)

请注意,hoist它必须满足某些法律,以确保它能够做到您所期望的"正确的事情":

hoist id = id

hoist (f . g) = hoist f . hoist g
Run Code Online (Sandbox Code Playgroud)

这些只是函子定律,保证hoist直观行为.

hoist包装Control.Monad.Morph模块中提供了mmorph您可以在此处找到的模块.主模块的底部有一个教程,教授如何使用该包