致力于置换monad变压器堆栈

时间:2011-12-05 09:57:40

标签: haskell monads monad-transformers

我发现monad变换器的一个问题是需要lift操作进入正确的monad。这里有一个lift并且没有坏,但有时会出现这样的函数:

fun = do
  lift a
  lift b
  c
  lift d
  lift e
  f

我希望能够编写这个函数:

fun = monadInvert $ do
  a
  b
  lift c
  d
  e
  lift f

这会使lift的数量减半并使代码更清晰。

问题是:对于monad是monadInvert可能的?应该如何创建这个功能?

加分点:为monad m定义MonadIO的实例。

这个问题的标题提到了排列:实际上,我们如何处理monad变换器堆栈的任意排列?

3 个答案:

答案 0 :(得分:16)

嗯,首先,你实际上并不需要这么多提升。对于monad变换器,以下标识包含:

lift c >>= lift . f = lift (c >>= f)
lift c1 >> lift c2  = lift (c1 >> c2)

写这个并不罕见:

x <- lift $ do
    {- ... -}

接下来是:当您使用 mtl monadLib 等库(即基于类型类的库而不是变换器)时,您实际上可以直接访问大多数底层monad:

c :: StateT MyState (ReaderT MyConfig SomeOtherMonad) Result
c = do
    x <- ask
    y <- get
    {- ... -}

最后,如果你真的需要大量提升尽管有这两点,你应该考虑编写自定义monad甚至使用完全不同的抽象。我发现自己使用自动机箭头进行有状态计算而不是状态monad。

答案 1 :(得分:10)

您可能对Tom Schrijvers和Bruno Oliveira的Monads, Zippers and Views, Virtualizing the Monad Stack感兴趣。

这并没有解决你关于减少升降机的观点,但这对你的“monad排列”来说是一个有趣的方法。问题

这是摘要:

  

这项工作旨在使monadic组件更具可重用性和可靠性   通过使用两种新技术来虚拟化monad来改变   堆栈:monad拉链和monad视图。 monad拉链是monad   通过忽略特定来创建虚拟monad堆栈的转换器   混凝土堆栈中的图层。 Monad视图提供了一个通用框架   对于monad堆栈虚拟化:他们采用monad zipper一步   进一步将其与各种其他虚拟化集成。   例如,特定视图允许限制访问monad   堆栈。此外,组件可以使用monad视图   提供类似于引用的调用机制来访问特定层   monad堆栈。有了这两种机制的组件要求   就monad堆栈形状而言,不再需要字面意思   反映在混凝土monad堆栈中,使这些组件更多   可重复使用且对变化具有鲁棒性。

答案 2 :(得分:1)

我很确定你所描述的内容对于IO来说是不可能的,IO总是最内在的monad:

来自MartinGrabmüller:Monad变形金刚一步一步,可在 http://www.grabmueller.de/martin/www/pub/

  

在本文档中,我们在eval6中调用liftIO来执行I / O操作。   在这种情况下,为什么我们需要解除?因为没有IO类   我们可以将类型实例化为。因此,对于I / O操作,我们   必须调用lift来向内发送命令

通常,对于比IO更少限制的monad,(例如Error和State)顺序对于语义仍然很重要,因此您不能仅仅为了使语法更方便而更改堆栈的顺序。

对于像Reader这样的一些monad(它们在堆栈中通勤),你的想法似乎并非显而易见。我不知道如何写它。我想这是一个类型类CentralMonad ReaderT是一个实例,有一些实现......