如果两个monad转换器类型不同,但它们的基本monad类型相同,是否有原则地构成两个monad转换器? [英] Is there a principled way to compose two monad transformers if they are of different type, but their underlying monad is of the same type?

查看:87
本文介绍了如果两个monad转换器类型不同,但它们的基本monad类型相同,是否有原则地构成两个monad转换器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以做很多事情来扩展这个问题.但这是一个用例:假设您有两个monad转换器ts,它们在同一个monad m上进行转换:

Not much I can do to expand the question. But here is a use case: let's say you have two monad transformers, t and s, transforming over the same monad m:

master :: (MonadTrans t, Monad m) => t m a b
slave  :: (MonadTrans t, Monad m) => s m a b

我想组成masterslave,以便当m原语被提升为ts时它们可以彼此通信.签名可能是:

And I want to compose master and slave such that they can communicate with each other when m primitives are lifted into t and s. The signature might be:

bound :: (MonadTrans t, MonadTrans s, Monad m, Monoid a) => t m a b -> s m a b -> (...)
But what is the type of (...) ?

用例,用加糖的符号表示:

A use case, in sugared notation:

master :: Monoid a => a -> t m a b
master a = do 
   a <- lift . send $ (a,False)     -- * here master is passing function param to slave
   ...                              -- * do some logic with a
   b <- lift . send $ (mempty,True) -- * master terminates slave, and get back result

slave :: Monoid a => (a -> b) -> s m a b
slave g = do 
    (a,end) <- lift receive
    case end of 
        True -> get >>= \b -> exit b  
        _    -> (modify (++[g a])) >> slave g

更新:sendreceivem类型的基元.

Update: send and receive are primitives of type m.

我很抱歉,如果这个例子看起来很虚假,或者太像协同程序,这个问题的实质与它无关,所以请忽略所有相似之处.但是要点是,以前无法将monads ts彼此合理地组合在一起,但是在将两个基本monads m包裹起来之后,它们现在可以被组合并作为单个函数运行.至于组合函数的类型,我真的不确定,因此可以理解一些方向.现在,如果这种抽象已经存在,而我只是不知道,那将是最好的.

I apologize if this example looks contrived, or resemble coroutines too much, the spirit of the question really has nothing to do with it so please ignore all similarities. But main point is that monads t and s couldn't be sensibly composed with each other before, but after both wrap some underlying monad m, they now could be composed and run as a single function. As for the type of the composed function, I'm really not sure so some direction is appreciated. Now if this abstraction already exist and I just don't know about it, then that would be best.

推荐答案

是.将mmorph软件包中的hoistlift组合在一起以执行此操作:

Yes. Combine hoist from the mmorph package with lift to do this:

bound
    :: (MonadTrans t, MonadTrans s, MFunctor t, Monad m)
    => t m () -> s m () -> t (s m) ()
bound master slave = do
    hoist lift master
    lift slave

要了解其工作原理,请研究hoist的类型:

To understand why this works, study the type of hoist:

hoist :: (MFunctor t) => (forall x . m x -> n x) -> t m r -> t n r

hoist可让您修改实现MFunctor的任何monad转换器的基本monad(多数).

hoist lets you modify the base monad of any monad transformer that implements MFunctor (which is most of them).

bound的代码所做的是让两个monad转换器在最终目标monad上达成共识,在这种情况下为t (s m).嵌套ts的顺序由您决定,所以我只是假设您要在外部使用t.

What the code for bound does is have the two monad transformers agree on a final target monad, which in this case is t (s m). The order in which you nest t and s is up to you, so I just assumed that you wanted t on the outside.

然后,只需使用hoistlift的各种组合来使两个子计算在最终的monad堆栈上达成共识.第一个是这样的:

Then it's just a matter of using various combinations of hoist and lift to get the two sub-computations to agree on the final monad stack. The first one works like this:

master :: t m r
hoist lift master :: t (s m) r

第二个是这样的:

slave :: s m r
lift slave :: t (s m) r

现在他们都同意了,所以我们可以在同一do块中对它们进行排序,这样就可以了.

Now they both agree so we can sequence them within the same do block and it will "just work".

要详细了解hoist的工作方式,建议您检查

To learn more about how hoist works, I recommend you check the documentation for the mmorph package which has a nice tutorial at the bottom.

这篇关于如果两个monad转换器类型不同,但它们的基本monad类型相同,是否有原则地构成两个monad转换器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆