我最近接触到了Kleisli的概念,每篇教程/链接/参考文献都通过以下结构来推动使用Kleisli:
- 组合返回单子(monad)的函数:对于
f: a -> m[b]
和g: b -> m[c]
这种情况——我认为单子的定义已经涵盖了这种情况——do/bind/for/flatMap
可以实现。不需要依赖Kleisli来完成。因此,在我看来,这不是Kleisli的"主要"用途。 - 插入配置信息:这一点说明,如果多个对象(类型、案例/数据类等)需要注入一个
Config
,则可以使用Kleisli构造来抽象掉可重复的注入过程。有许多实现方式(例如Scala中的implicit
),可能并不需要调用Kleisli。同样地,我认为这也不是Kleisli的"主要"用途。 - Monad变换器: 我对此没有很深刻的理解,但以下是我的解释:如果你需要“组合monad”,你需要一种允许你参数化monad本身的构造。例如,
M1[M2[M1[M2[a]]]]
可以转换为[M1[M2[a]]]
,这个结果可能(我可能会错)通过跨monadic边界进行压缩以与a -> M3[b]
(比如)组合。为了实现这个目的,我们可以使用Kleisli三元组并调用构造函数,因为如果你从头开始做,你可能只是重新发明了Kleisli。这似乎是证明使用Kleisli的一个很好的候选案例。这是正确的吗?
我认为上述#1-#2
是“次要用途”。也就是说,如果你确实使用Kleisli构造函数,你还可以获得返回monad的函数组合模式和配置注入。然而,它们不能成为支持Kleisli强大能力的激励问题。
在假定使用最不强大的抽象来解决手头的问题的前提下,有哪些激励性问题可以用来展示它们的使用?
备选论点: 完全有可能我完全错了,我的 Kleisli 理解不正确。我缺乏必要的范畴论背景,但是它可以作为单子的替代品使用,它们(Kleisli)是我们在函数世界问题中看待问题的范畴论镜头(即,Klesli 只是包装了一个单子函数a -> M[b]
,现在我们可以在更高的抽象层次上工作,在这个层次上,函数是“操作”的对象,而不是“使用”的对象)。因此,Kleisli 的使用可以简单地理解为“带 Kleisli 的函数式编程”。如果这是真的,那么就应该存在一种情况,Kleisli 可以比现有结构更好地解决问题,然后我们又回到了一个“激励问题”的问题。同样有可能的是,并没有这样的“激励问题”,如果它只是提供了对同一问题的“不同”解决方案的“镜头”。哪一个呢?
能够获得一些输入以重构 Kleisli 的需求将非常有帮助。
List
的Kleisli
箭头的Choice
变换”,就像这样,你就有了适当的强大基础来表达你的思想。 - luquif :: a -> b
和一个单子m
,相应的Kleisli箭头是一个新函数f' :: a -> m b
。(我假设Scala也是如此,只是使用不同的语法。) - chepner