LiftM 函数是否被剥夺了其一元本质?

bob*_*bob 4 monads haskell functional-programming applicative lifting

monad 和 applicative 的区别在于前者可以根据之前的结果选择下一个计算:

(\x -> if x == 1 then (\_ -> []) else (\y -> (\z -> \w -> [x,y,z]) =<< sqr) =<< (+1)) =<< (+1) $ 0
--                      ^

(\w x -> if x == 1 then (\_ _ -> []) else (\y z -> [x,y,z])) <*> (+1) <*> (+1) <*> sqr $ 0
--                        ^^^
Run Code Online (Sandbox Code Playgroud)

一元计算可以使计算短路,而对于应用计算,无论我们提供什么输入,我们都必须使用整个计算结构并运行所有效果。

让我们将其与liftM

liftM3 (\x -> if x == 1 then (\_ _ -> []) else (\y z -> [x,y,z])) (+1) (+1) sqr $ 0
--                             ^^^
Run Code Online (Sandbox Code Playgroud)

这似乎是变相的应用风格。即使我用 monadic applicator 替换了电梯操作员,整个结构似乎也失去了它的 monadic 属性:

appM3 w f x g y h z =
  f(\x' -> g(\y' -> h(\z' -> w x' y' z') z) y) x

appM3 (\x -> if x == 1 then (\_ _ _ -> []) else (\y z _ -> [x, y, z])) (=<<) (+1) (=<<) (+1) (=<<) sqr $ 0
--                            ^^^^^
Run Code Online (Sandbox Code Playgroud)

这是否意味着必须始终手动编码正确的 monadic 计算?我知道 do 符号,但底层机制似乎类似于宏扩展(如果这是无稽之谈,请纠正我),所以它并没有真正反驳我的假设。

Car*_*arl 11

你是对的。liftMfmap,而且liftM2liftA2。它们的存在是标准库中仍然僵化的历史产物,而不是真正需要 monadic 绑定操作的力量的东西。

标准库的早期版本没有做FunctorApplicative的超类Monad。(如果你回溯得足够远,它Applicative甚至不存在。)因此,为了实用起见,创建了执行相同操作的函数以使用 with Monad。它们在 Applicative-Monad 提案中的转换中幸存下来,因为它们仍然用于一个目的——如果您手动实现所有类,您可以使用它们来根据代码实现类型FunctorApplicative实例Monad