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)?
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With