如何通用地组合 return 不同单子的单子函数?

How to generically compose monadic functions that return different monads?

据我了解,如果您有许多 f: a -> m[b] 类型的函数,并且只要它们的所有 return 值都包含在 m 中,您应该能够通过 do/bind/flatMap:

f: A -> M[B]
g: B -> M[C]
h: C -> M[D]

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

如何编写在 monad "boxes" 中不同但值 inside 是 "chainable" 的函数?

f: A -> M[B]
g: B -> N[C]
h: C -> P[D]

我从来没有 seen/read 这种情况,我知道我们可以 lift monad 但这会破坏 IMO 的目的。这是 monadic 构造的限制吗?我们甚至可以将它们链接起来吗?解决这个问题的规范方法是什么?

正如@Luis Miguel Mejía Suárez 所说,单子不构成。如果你有 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] 并将它们组合为 monad,但这远非直截了当。

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

目前,如果你需要堆叠效果,你更有可能使用无标记最终使用一个组合效果,使用 MTL 类型 类 在 monadic 接口旁边提供 state/reader/writer/etc 能力。如果您必须在效果之间进行转换,则必须通过自然转换。

总而言之,这个问题通常没有得到解决,甚至现在 Haskell 社区也在寻找一些新的解决方案。即使是现在,像 Eff and Polysemy 这样的库也有发展,据我所知,它们是 freer/eff monad,但具有内置编译器支持。目前,您最多可以预先决定综合效果或通过 TTFI 和 MTL 推迟选择。只是把不同的单子放在一起……如果不思考和写下如何做是不可能的。