如何通用地组合 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 推迟选择。只是把不同的单子放在一起……如果不思考和写下如何做是不可能的。
据我了解,如果您有许多 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 推迟选择。只是把不同的单子放在一起……如果不思考和写下如何做是不可能的。