变形金刚之下的变革

目前,我对monad变压器有点困难。 我正在定义一些使用变形金刚的不同的非确定性关系。 不幸的是,我无法理解如何从一个有效的模型转换到另一个有效的模型。

假设这些关系是“foo”和“bar”。 假设“foo”将As和Bs关联到Cs; 假设“bar”将Bs和Cs与Ds相关联。 我们将用“foo”来定义“bar”。 为了使事情更有趣,这些关系的计算将以不同的方式失败。 (因为bar关系依赖于foo关系,所以它的失败情况是一个超集。)因此,我给出了以下类型定义:

data FooFailure = FooFailure String
data BarFailure = BarSpecificFailure | BarFooFailure FooFailure
type FooM = ListT (EitherT FooFailure (Reader Context))
type BarM = ListT (EitherT BarFailure (Reader Context))

然后,我希望能够用以下函数签名来编写关系:

foo :: A -> B -> FooM C
bar :: B -> C -> BarM D

我的问题是,当为“bar”写定义时,我需要能够从“foo”关系接收错误并在“bar”空间中正确表示它们。 所以我会很好地处理表单的功能

convert :: (e -> e') -> ListT (EitherT e (Reader Context) a
                     -> ListT (EitherT e' (Reader Context) a

我甚至可以通过运行ListT,在EitherT上映射,然后重新组装ListT(因为它发生m [a]可以转换为ListT ma)来编写这个小野兽。 但这似乎......凌乱。

有一个很好的理由,我不能只是运行一台变压器,在它下面做一些事情,并且一般地“放回去”。 我运行的变压器可能会产生影响,我无法神奇地将它们撤消。 但是有没有什么方法可以将一个函数提升到变换堆栈中,为我做一些工作,所以我不必编写上面显示的convert函数?


我认为转换是一个很好的答案,并使用Control.Monad.MorphControl.Monad.Trans.Either它可以(几乎)很简单地编写:

convert :: (Monad m, Functor m, MFunctor t)
           => (e -> e')
           -> t (EitherT e m) b -> t (EitherT e' m) b
convert f = hoist (bimapEitherT f id)

轻微的问题是, ListT不是一个实例MFunctor 。 我认为这是抵制ListT的作者,因为它不遵循单子变换法则,因为很容易编写一个类型检查实例

instance MFunctor ListT where hoist nat (ListT mas) = ListT (nat mas)

无论如何,一般来看看Control.Monad.Morph来处理(部分)变压器堆栈上的自然变换。 我认为这符合将函数“足够”提升到堆栈的定义。

链接地址: http://www.djcxy.com/p/13541.html

上一篇: Transformation under Transformers

下一篇: Paypal fees in a chained or parallel payment