Monads在实践中作为Monoids

时间:2017-01-09 19:13:18

标签: scala functional-programming monads

我试图以更实际的方式理解monad和monoids之间的关系。如果这个问题毫无意义,我会事先道歉,我还在苦苦挣扎。

例如,假设我有:

trait Monoid[T] {
  def zero: T
  def combine: (T,T) => T
}

和(来自here):

trait Monad[+M[_]] {
  def unit[A](a: A): M[A]
  def bind[A, B](m: M[A])(f: A => M[B]): M[B]
}

是否可以在Monad和Monoid特征之间建立关系,例如我可以将Monad视为Monoid(假设我正确理解Monad是Monoid的特例)?

1 个答案:

答案 0 :(得分:4)

如果使用unitjoin代替unitbind编写monad,您可能会更容易看到连接:

trait Monoid[T] {
  def zero: T
  def combine: (T,T) => T
}

trait Monad[M[_]] {
  def unit[A]: A => M[A]
  def join[A]: M[M[A]] => M[A]
}

加入是Scala的flatten,绑定是Scala的flatMap

请注意,要仅使用unitflatten/join定义monad,您还必须提供方法map[A](m: M[A])(f: A => B): M[B]。这是因为monad实际上是一个(endo)仿函数,具有两个自然变换,单位和连接。由于它是一个仿函数,因此它具有map功能。根据您的代码设计,map应与Monad特征中的unitjoin一起定义,或者从Monad特征扩展的Functor特征继承。

为了完整起见,让我说明定义monad的所有三种可能方式:

  • unit + flatMap
  • unit + flatten + map
  • unit + compose

所有三个都可以使用另外两个中的一个来表达。我将跳过代码来演示这一点,因为它与问题没有直接关系,但如果需要,我可以在编辑中添加它。