Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monads as Monoids in practice

I am trying to understand the relationship between monads and monoids in more practical ways. I apologize in advance if this question makes no sense, I'm still struggling.

Suppose for example, I have:

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

and (from here):

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

Is there a relationship that can be established between Monad and Monoid traits, such as that I can treat a Monad as a Monoid (assuming I understand correctly that a Monad is a special case of a Monoid)?

like image 889
Will I Am Avatar asked Jan 09 '17 19:01

Will I Am


1 Answers

You will probably see the connection more easily if you write a monad using unit and join instead of unit and 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 is Scala's flatten, and bind is Scala's flatMap.

Note that in order to define a monad just by using unit and flatten/join, you must also provide the method map[A](m: M[A])(f: A => B): M[B]. This comes from the fact that monad is actually an (endo)functor with two natural transformations, unit and join. Since it's a functor, it has the map functionality. Depending on your code design, map should be either defined together with unit and join inside your Monad trait or inherited from some Functor trait that would be extended by your Monad trait.

For completeness, let me state all three possible ways of defining a monad:

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

All three can be expressed using one of the other two. I will skip the code to demonstrate this since it's not directly related to the question, but I can add it in edit if needed.

like image 169
slouc Avatar answered Nov 15 '22 07:11

slouc