变形金刚下的转型

tvy*_*ynr 7 monads haskell lifting

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

假设这些关系是"foo"和"bar".假设"foo"将As和Bs与Cs联系起来; 假设"bar"将Bs和Cs与Ds联系起来.我们将用"foo"来定义"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))
Run Code Online (Sandbox Code Playgroud)

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

foo :: A -> B -> FooM C
bar :: B -> C -> BarM D
Run Code Online (Sandbox Code Playgroud)

我的问题是,写"酒吧"的定义的时候,我需要能够从"富"的关系接收错误和正确地表示他们在"酒吧"的空间.所以我可以使用表单的功能

convert :: (e -> e') -> ListT (EitherT e (Reader Context) a
                     -> ListT (EitherT e' (Reader Context) a
Run Code Online (Sandbox Code Playgroud)

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

有一个很好的理由我不能只运行变压器,在它下面做一些东西,并且通常"把它放回去"; 我跑的变压器可能有效果,我不能神奇地撤消它们.但是有一些方法我可以将一个函数提升到变压器堆栈中,为我做一些工作,所以我不必编写convert上面显示的函数吗?

J. *_*son 3

我认为 Convert 是一个很好的答案,并且使用Control.Monad.MorphandControl.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)
Run Code Online (Sandbox Code Playgroud)

一个小问题是这ListT不是 的实例MFunctor。我认为这是作者的抵制ListT,因为它不遵循 monad 转换器定律,因为编写类型检查实例很容易

instance MFunctor ListT where hoist nat (ListT mas) = ListT (nat mas)
Run Code Online (Sandbox Code Playgroud)

无论如何,通常看一下Control.Monad.Morph如何处理变压器堆栈(部分)上的自然变换。我想说这符合将函数“刚好足够”提升到堆栈中的定义。