致力于置换monad变压器堆栈

Ten*_*ner 15 monads haskell monad-transformers

我发现monad变换器的一个问题是需要lift将操作转换为正确的monad.单lift在这里和那里也不错,但有时也有功能类似如下:

fun = do
  lift a
  lift b
  c
  lift d
  lift e
  f
Run Code Online (Sandbox Code Playgroud)

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

fun = monadInvert $ do
  a
  b
  lift c
  d
  e
  lift f
Run Code Online (Sandbox Code Playgroud)

这会减少lifts 的数量并使代码更清晰.

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

加分点:定义它monad m的实例MonadIO.

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

小智 16

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

lift c >>= lift . f = lift (c >>= f)
lift c1 >> lift c2  = lift (c1 >> c2)
Run Code Online (Sandbox Code Playgroud)

写作并不罕见:

x <- lift $ do
    {- ... -}
Run Code Online (Sandbox Code Playgroud)

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

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

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


Nic*_* Wu 10

你可能感兴趣于Monads,Zippers和Views,虚拟化Monad Stack by Tom Schrijvers和Bruno Oliveira.

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

这是摘要:

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