我知道monad是什么以及如何使用它们。我不明白的是是什么,让我们说,Option
一个monad?
在Haskell中,monad Maybe
是一个monad,因为它是从Monad
类实例化的(它具有至少2个必要函数return
和bind
,它们使类{{1}确实,一个monad)。
但是在Scala,我们得到了这个:
Monad
与monad无关。
如果我在Scala中创建自己的类,默认情况下它是monad吗?为什么不呢?
答案 0 :(得分:56)
Monad
是一个概念,如果你愿意,它是一个抽象的接口,它只是定义了一种组合数据的方式。
Option
通过flatMap
支持作曲,而且几乎所有佩戴" monad徽章所需的一切"。
从理论的角度来看,它也应该:
unit
操作(return
)以创建裸值的monad,如果Option
是Some
构造函数< / LI>
但Scala没有严格执行此规定。
Scala中的Monads是一个更宽松的概念,在Haskell中,这种方法更实用。 从语言的角度来看,monad唯一与之相关的是能够用于理解的能力。
flatMap
是基本要求,您可以可选提供map
,withFilter
和foreach
。
然而,对于Monad
类型类没有严格的一致性,就像Haskell一样。
以下是一个例子:让我们定义自己的monad。
class MyMonad[A](value: A) {
def map[B](f: A => B) = new MyMonad(f(value))
def flatMap[B](f: A => MyMonad[B]) = f(value)
override def toString = value.toString
}
如您所见,我们仅实施map
和flatMap
(以及toString
作为商品)。
恭喜,我们有一个monad!我们试一试:
scala> for {
a <- new MyMonad(2)
b <- new MyMonad(3)
} yield a + b
// res1: MyMonad[Int] = 5
尼斯!我们没有进行任何过滤,因此我们不需要实施withFilter
。此外,由于我们正在产生价值,我们也不需要foreach
。基本上你实现了你想要支持的任何东西,没有严格的要求。如果您尝试过滤for-comprehension并且尚未实现withFilter
,那么您只会收到编译时错误。
答案 1 :(得分:13)
通过鸭子类型(部分)实现FilterMonadic
特征的任何东西都被认为是Scala中的monad。这与在Haskell或Monad
typeclass in scalaz中表示monad的方式不同。但是,为了使Scala中的for
理解语法糖受益,对象必须暴露FilterMonadic
特征中定义的一些方法。
此外,在Scala中,Haskell return
函数的等价物是yield
关键字,用于从for
理解中生成值。 yield
的贬低是对“monad”的map
方法的调用。
答案 2 :(得分:9)
我说的方式是,monads之间的区别在于设计模式与一流抽象。 Haskell以Monad
类型的形式具有后者。但是如果你的类型具有(或可以实现)monadic操作并遵守法律,那么这也是monad。
现在,您可以在Java 8的库中看到monads作为设计模式。 Java 8中的Optional
和Stream
类型带有与Haskell of
对应的静态return
方法和flatMap
方法。但是没有Monad
类型。
介于两者之间你也有“鸭子式”方法,正如IonuţG。Stan的回答所说的那样。 C#也有这个 - LINQ语法不依赖于特定类型,而是可以与任何实现某些方法的类一起使用。
答案 3 :(得分:0)
Scala本身不提供monad的概念。您可以将monad表示为类型类,但Scala也不提供类型类的概念。但是猫是。因此,您可以在Scala中使用必要的样板创建Monad,例如巧妙地使用了特征和隐式特性,或者您可以使用开箱即用的猫来提供monad特征。作为比较,Haskel提供了monad作为语言的一部分。关于您的特定问题,Option可以表示为monad,因为它具有flatMap方法和unit方法(例如,将值包装在Some或Future中)。