我正在学习Scala中的函数式编程,我学习了术语monad。简而言之,monad是:
trait M[A] {
def flatMap[B](f: A => M[B]): M[B]
}
def unit[A](x: A): M[A]
我知道monad只是一个基于上述2条规则的概念。我们可以在现实世界中遇到许多monad,例如List
,Future
....
我不知道的唯一一个问题是:为什么我们应该将术语“monad”比作理解List apis,Future apis或者任何apis ... ...理解monad帮助我们编写更好的代码或者设计更好的功能代码结构。
由于
答案 0 :(得分:7)
因为Monad已经是类别理论中的一个已知术语。还有3个非常重要的Monad法律,Monad必须坚持。
理论上,我们可以将Monads称为任何我们想要的,即“FlatMappable”或“Bindable”,但“Monad”这个名称已经是功能编程社区中的既定术语,并且与Monad法律密切相关。
至于为什么你应该学会欣赏Monads而不是单独学习每个api,这都是关于知识的抽象和重用。通常,当我们看一个新概念时,我们会将它们与我们已经知道的概念进行比较。
如果您已经了解未来Monad,那么理解Task Monad会更容易。
值得一提的是,Scala中的for-comprehensions
专门用于Monads。事实上,for-comprehensions
只是flatMap
和map
的语法糖(还有filter
,但这与Monads并不相关)。因此,如果某些东西是Monad实例,则可以使用这一额外的句法糖。
一旦你完全掌握了抽象,你就可以利用像Monad变换器这样的概念,其中Monad的实际类型并不那么重要。
最后,为了完整起见,这是Monad法律:
M[F].pure(x).flatMap(f) == f(x)
m.flatMap(pure(_)) == m
m.flatMap(f).flatMap(g) == m.flatMap(x => f(x).flatMap(g))
答案 1 :(得分:0)
关于Monad API与具体API:
一个例子可能是Free Monad模式。它主要使用(至少)两个monad:第一个是包装你的DSL表达式,第二个是效果monad,即你解释你的表达式的模态(Option对应于可能失败的东西,Future也增加了延迟等)。
更具体一点:考虑一个你有一些延迟的任务,你决定使用期货。你将如何进行单元测试呢?返回一些期货,然后使用Await?除了增加不必要的复杂性,你可能会遇到一些问题。而且你实际上不需要使用Futures进行一些测试。答案是参数化应该使用期货与Monad的方法,这样你就可以使用Identity monad或Option,而忘记上述问题。