37

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

在 Haskell 中,一个 monadMaybe是一个 monad,因为它是从Monadclass 实例化的(它至少有 2 个必要的函数returnbind这使得 classMonad实际上是一个 monad)。

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

sealed abstract class Option[+A] extends Product with Serializable { ... }
trait Product extends Any with Equals { ... }

与单子无关。

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

4

4 回答 4

61

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

Option通过 支持组合flatMap,这几乎就是佩戴“monad 徽章”所需的一切。

从理论上讲,它还应该:

  • 支持一个unit操作(return在 Haskell 术语中)从一个裸值创建一个 monad,在这种情况下OptionSome构造函数
  • 尊重一元法则

但这并不是 Scala 严格执行的。

scala 中的 Monad 是一个比 Haskell 更宽松的概念,而且这种方法更实用。从语言的角度来看,monad 唯一相关的是用于理解的能力。

flatMap是一项基本要求,您可以选择提供map和。withFilterforeach

然而,没有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作为商品)。恭喜,我们有一个单子!让我们试一试:

scala> for {
  a <- new MyMonad(2)
  b <- new MyMonad(3)
} yield a + b
// res1: MyMonad[Int] = 5

好的!我们没有做任何过滤,所以我们不需要实现withFilter. 此外,由于我们正在产生一个值,因此我们也不需要foreach。基本上你可以实现任何你想支持的东西,没有严格的要求。如果您尝试在 for-comprehension 中进行过滤并且您还没有实现withFilter,那么您只会得到一个编译时错误。

于 2014-08-18T10:35:20.483 回答
13

任何(部分)通过鸭子类型实现的东西,这个FilterMonadic特征都被认为是 Scala 中的一个 monad。这与 Haskell 中 monad 的表示方式或Monadscalaz中的类型类不同。然而,为了受益for于 Scala 中的理解语法糖,对象必须公开FilterMonadictrait 中定义的一些方法。

此外,在 Scala 中,Haskellreturn函数的等效项是yield用于从推导式中产生值的关键字for。脱糖是对“monad”方法的yield调用。map

于 2014-08-18T10:40:56.470 回答
9

我的说法是,作为设计模式的 monad与一流的抽象之间存在着新的区别。Haskell 有后者,以Monad类型类的形式。但是,如果您有一个具有(或可以实现)单子操作并遵守法律的类型,那也是单子。

如今,您可以将 monad 视为 Java 8 库中的一种设计模式。Java 8 中的OptionalandStream类型带有一个of对应于 Haskell 的静态方法return和一个flatMap方法。但是没有Monad类型。

正如 Ionuț G. Stan 的回答所指出的那样,介于两者之间的某个地方也有“鸭式”方法。C# 也有这一点——LINQ 语法不依赖于特定类型,而是可以与实现某些方法的任何类一起使用。

于 2014-08-18T17:43:53.177 回答
0

Scala 本身不提供 monad 的概念。您可以将 monad 表示为类型类,但 Scala 也不提供类型类的概念。但猫确实如此。因此,您可以使用必要的样板在 Scala 中创建 Monad,例如巧妙地使用特征和隐式,或者您可以使用提供开箱即用的 monad 特征的猫。作为比较,Haskel 提供了单子作为语言的一部分。关于您的具体问题,Option 可以表示为 monad,因为它具有 flatMap 方法和 unit 方法(例如,将值包装在 Some 或 Future 中)。

于 2020-10-13T14:23:10.100 回答