7

我无能为力来扩大这个问题。但这里有一个用例:假设你有两个 monad 转换器,t并且s,在同一个 monad 上进行转换m

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

而且我想编写masterand以便在将原语提升到andslave时它们可以相互通信。签名可能是:mts

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

一个用例,用糖化符号表示:

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

更新:sendandreceive是 type 的原语m

如果这个例子看起来很做作,或者太像协程,我深表歉意,问题的精神真的与它无关,所以请忽略所有相似之处。但主要的一点是 monadts之前不能明智地相互组合,但是在它们都包装了一些底层 monad 之后m,它们现在可以组合并作为单个函数运行。至于组合函数的类型,我真的不确定,所以有些方向是值得赞赏的。现在,如果这种抽象已经存在而我只是不知道,那将是最好的。

4

1 回答 1

8

是的。hoistmmorph包中结合来lift执行此操作:

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

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

hoist允许您修改实现的任何 monad 转换器的基本 monad MFunctor(这是其中的大多数)。

代码bound所做的是让两个 monad 转换器就最终目标 monad 达成一致,在这种情况下是t (s m). t你嵌套的顺序s取决于你,所以我只是假设你想要t在外面。

然后只需要使用 和 的各种组合hoistlift让两个子计算就最终的 monad 堆栈达成一致。第一个是这样工作的:

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

第二个是这样工作的:

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

现在他们都同意了,所以我们可以在同一个do块中对它们进行排序,它会“正常工作”。

要了解有关如何hoist工作的更多信息,我建议您查看该软件包的文档,该文档底部有一个很好的教程。mmorph

于 2013-08-21T18:53:02.760 回答