Monads在实践中作为Monoids

Wil*_* Am 5 monads functional-programming scala

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

例如,假设我有:

trait Monoid[T] {
  def zero: T
  def combine: (T,T) => T
}
Run Code Online (Sandbox Code Playgroud)

和(从这里):

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

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

slo*_*ouc 5

如果您使用unitandjoin而不是unitand编写 monad,您可能会更容易看到连接bind

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]
}
Run Code Online (Sandbox Code Playgroud)

Join 是 Scala 的flatten,而 bind 是 Scala 的flatMap

请注意,为了仅使用unitand定义 monad flatten/join,您还必须提供方法map[A](m: M[A])(f: A => B): M[B]。这是因为 monad 实际上是一个(endo)函子,具有两个自然变换,unit 和 join。因为它是一个函子,所以它有这个map功能。根据你的代码设计,map应该与你的 Monad trait一起定义unitjoin在你的 Monad trait 中定义,或者继承自某些 Functor trait,这些 Functor trait 将被你的 Monad trait 扩展。

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

  • 单元 + 平面图
  • 单位 + 展平 + 地图
  • 单元 + 组合

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