究竟是什么让Option成为Scala中的monad?

时间:2014-08-18 10:30:10

标签: scala haskell functional-programming monads maybe

我知道monad是什么以及如何使用它们。我不明白的是是什么,让我们说,Option一个monad?

在Haskell中,monad Maybe是一个monad,因为它是从Monad类实例化的(它具有至少2个必要函数returnbind,它们使类{{1}确实,一个monad)。

但是在Scala,我们得到了这个:

Monad

与monad无关。

如果我在Scala中创建自己的类,默认情况下它是monad吗?为什么不呢?

4 个答案:

答案 0 :(得分:56)

Monad是一个概念,如果你愿意,它是一个抽象的接口,它只是定义了一种组合数据的方式。

Option通过flatMap支持作曲,而且几乎所有佩戴" monad徽章所需的一切"。

从理论的角度来看,它也应该:

  • 以Haskell术语支持unit操作(return)以创建裸值的monad,如果OptionSome构造函数< / LI>
  • 尊重monadic laws

但Scala没有严格执行此规定。

Scala中的Monads是一个更宽松的概念,在Haskell中,这种方法更实用。 从语言的角度来看,monad唯一与之相关的是能够用于理解的能力。

flatMap是基本要求,您可以可选提供mapwithFilterforeach

然而,对于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
}

如您所见,我们仅实施mapflatMap(以及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中的OptionalStream类型带有与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中)。