如何一般地组合返回不同 monad 的 monadic 函数?

PhD*_*PhD 3 monads haskell functional-programming scala

据我了解,如果您有许多该类型的函数,f: a -> m[b]并且只要它们都返回包含在其中的值,m您应该能够通过do/bind/flatMap以下方式将它们链接起来:

f: A -> M[B]
g: B -> M[C]
h: C -> M[D]
Run Code Online (Sandbox Code Playgroud)

通过>>=or flatMap(Scala)链接起来相当简单。

如何组合在 monad“盒子”中不同但里面的值是“可链接的”的函数?

f: A -> M[B]
g: B -> N[C]
h: C -> P[D]
Run Code Online (Sandbox Code Playgroud)

我从未见过/读过这种情况,我知道我们可以使用liftmonad,但这会破坏 IMO 的目的。这是 monadic 结构的限制吗?我们甚至可以链接它们吗?解决这个问题的规范方法是什么?

Mat*_*zok 8

正如@Luis Miguel Mejía Suárez 所说,monad 不会组合。如果你有M[A]N[B]并且O[C]你不能只是把它们组合成……到底是什么?

您可能希望将它们组合成类似M[N[O[D]]]. 但flatMap只能在最外面的 monad 上工作。如果您让计算遍历所有层,则除了最外层之外,每一层都必须有一个 monad 转换器。

可以开箱即用地生成这种组合类型吗?也不要因为M[N[O[D]]]不会是一样的O[N[M[D]]],并应该在决定确定的方式秩序的某种方式。

你可以通过自然变换成Target[_]从各类型的,这将让你变换 M[A]N[B]O[C]进入Target[A]Target[B]Target[C]和它们合并为单子,但这是远非那么简单。

然后有一些方法,而不是使用特定的M[_], N[_], O[_],您将它们作为参数传递,将 Target 作为参数传递,并且以某种方式能够添加和影响类型并执行它 - Freer,其优化的形式Eff和代数效果是这样一种方式来创建一个type=level 效果列表并添加和删除它们(通过解释/运行一层)。据我所知,这些尝试是成功的,因为它们总体上使他们承诺的事情成为可能……但是精神上的开销使它们变得非常不切实际,并且对大多数人来说难以理解。确切地说,不是直截了当的。有时也会产生误导,因为他们有时会假装我们解释效果的顺序无关紧要,但实际上确实如此。

目前,如果您需要堆叠效果,您更有可能使用无标签 final 来在任何地方使用组合效果,使用 MTL 类型类在 monadic 接口旁边提供状态/读取器/写入器/等功能。如果必须在效果之间进行转换,则必须通过自然转换。

总而言之,总的来说这个问题没有解决,甚至现在 Haskell 社区也在寻找一些新的解决方案。即使现在也有像EffPolysemy这样的库的开发,据我所知,它们是更自由的/ eff monad,但具有内置的编译器支持。目前,您最多可以预先决定聚合效果,或者通过 TTFI 和 MTL 推迟选择。只是将不同的 monad 组合在一起......如果不思考和编写如何做是不可能的。