Монады как моноиды на практике


Я пытаюсь понять отношения между монадами и моноидами более практическими способами. Я заранее извиняюсь, если этот вопрос не имеет смысла, я все еще борюсь.

Предположим, например, что у меня есть:
trait Monoid[T] {
  def zero: T
  def combine: (T,T) => T
}

И (из здесь):

trait Monad[+M[_]] {
  def unit[A](a: A): M[A]
  def bind[A, B](m: M[A])(f: A => M[B]): M[B]
}
Существует ли связь, которая может быть установлена между монадой и Моноидными чертами, например, что я могу рассматривать монаду как моноид (предполагая, что я правильно понимаю, что монада является частным случаем моноида)?
1 5

1 ответ:

Вы, вероятно, увидите связь легче, если вы напишете монаду, используя unit и join вместо unit и 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]
}

Join-это Scala flatten, а bind-Scala flatMap.

Обратите внимание, что для определения монады только с помощью unit и flatten/join необходимо также предоставить метод map[A](m: M[A])(f: A => B): M[B]. Это происходит из того факта, что монада на самом деле является (Эндо)функтором с двумя естественными преобразованиями, единицей и соединением. Поскольку это функтор, он имеет функциональность map. Зависящий в вашем коде map должен быть либо определен вместе с unit и join внутри вашего признака монады, либо унаследован от некоторого признака функтора, который будет расширен вашим признаком монады. Для полноты изложения приведу все три возможных способа определения монады:
  • unit + flatMap
  • unit + flatten + map
  • unit + compose
Все три могут быть выражены с помощью одного из двух других. Я пропущу код, чтобы продемонстрировать это, так как это не имеет прямого отношения к вопросу, но я могу добавить его в edit, если это необходимо.