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

アレッ*_*ックス 36 monads haskell functional-programming scala maybe

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

在Haskell中,monad Maybe是一个monad,因为它是从Monad类中实例化的(它具有至少2个必要的函数return,bind并且实现了类Monad,实际上是monad).

但是在Scala我们有这个:

sealed abstract class Option[+A] extends Product with Serializable { ... }
trait Product extends Any with Equals { ... }
Run Code Online (Sandbox Code Playgroud)

没有任何与monad相关的东西.

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

Gab*_*lla 56

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

Option支持组合通过flatMap,这几乎是穿"monad徽章"所需的一切.

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

  • 支持一个unit操作(return在Haskell术语中)从一个裸值创建一个monad,如果OptionSome构造函数
  • 尊重一元法律

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

scala中的Monads是一个更宽松的概念,在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
}
Run Code Online (Sandbox Code Playgroud)

如你所见,我们只是实施mapflatMap(以及toString作为商品).恭喜,我们有一个monad!我们来试试吧:

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

太好了!我们没有进行任何过滤,因此我们不需要实现withFilter.此外,由于我们正在产生价值,我们也不需要foreach.基本上你实现了你想要支持的任何东西,没有严格的要求.如果您尝试过滤for-comprehension并且尚未实现withFilter,则只会出现编译时错误.

  • "因此Option不知道它本身就是一个monad?与Haskell中的Maybe不同." 在Haskell`Monad`只是一个类.简单地为Monad定义类型类并不足以真正成为monad.必须正确定义所需的功能.如果我为我自己的类型`Foo`创建一个类型类Monad但是搞砸了`bind`的实现,例如,`Foo`不是monad.完全可以在Scala中创建Monad类的等价物 - 我认为它实际上是在Scalaz中完成的. (6认同)
  • 所以Option不知道它本身就是monad?与Haskell中的Maybe不同. (3认同)
  • 确切地说,在Scala中,具有flatmap的所有内容都被视为"monad",它可以用于for -reherehension(相当于haskell中的do-block) (2认同)

Ion*_*tan 13

任何(部分)实现的东西,通过鸭子打字,FilterMonadic特征被认为是Scala中的monad.这与在Haskell中表示monad或Monad在scalaz中表示类型类的方式不同.但是,为了使forScala 中的理解语法糖受益,对象必须暴露FilterMonadic特征中定义的一些方法.

此外,在Scala中,Haskell return函数的等价物是yield用于从for理解中生成值的关键字.desugaring yieldmap对"monad"方法的调用.

  • 这意味着编译器将for理解视为一种宏,并将其替换为对"flatMap","map","foreach"和/或"withFilter"的调用.对这种翻译进行类型检查,而不是为了理解.这就是为什么我说这是打字的原因.任何看起来像"FilterMonadic"的东西都会被理解所接受. (4认同)

Lui*_*las 9

我所说的方式是,monads作为一种设计模式一流的抽象之间正在出现区别.Haskell以Monad类型类的形式具有后者.但是如果你的类型具有(或可以实现)monadic操作并遵守法律,那么这也是一个monad.

现在,您可以在Java 8的库中看到monads作为设计模式.Java 8中的OptionalStream类型带有一个of与Haskell对应的静态方法return和一个flatMap方法.但是没有Monad类型.

介于两者之间你也有"鸭式"的方法,正如IonuţG.Stan的回答所说的那样.C#也有这个 - LINQ语法不依赖于特定类型,而是可以与任何实现某些方法的类一起使用.

  • 实际上,*不能*是Java中的`Monad`类型,因为`Monad`是更高级的,但Java没有更高的参数多态性. (3认同)