trait Monad[M[_]] extends Applicative[M] {
def flatMap[A, B](ma: M[A])(f: A => M[B]): M[B]
def join[A](mma: M[M[A]]): M[A] =
flatMap(mma)(ma => ma)
def ap[A, B](f: M[A => B])(ma: M[A]): M[B] =
flatMap(f)({ g => flatMap(ma)({ a => pure(g(a)) }) })
}
object Monad {
import Functor._
implicit class MonadOps[A, M[_]: Monad](ma: M[A]) extends FunctorOps[A, M](ma) {
def flatMap[B](f: A => M[B]): M[B] =
[Monad[M]].flatMap(ma)(f)
implicitly
def >>=[B](f: A => M[B]): M[B] =
flatMap(f)
}
}
In category theory, a monad builds on a certain morphism between
categories. In functional programming, this allows a function of type
A => F[B]
to be lifted to a function of type
F[A] => F[B]
for some type constructor
F
.
.--------------. .-------------------.
| Category _ | | Category F[_] |
|--------------| |-------------------|
| A ~~~~~~~~~~~ pure ~~~~~> F[A] |
| B ~~~~~~~~~~~ pure ~~~~~> F[B] |
| A ======================> F[B] |
| | | | |
| '~~~ flatMap ~~> F[A] => F[B] |
'--------------' '-------------------'
This diagram can be read as:
_
contains objects of type A
and B
, and a morphism from A
to
F[B]
, which is in the category F[_]
F[_]
contains objects of type
F[A]
and F[B]
, and a morphism from
F[A]
to F[B]
F[_]
converts the A
object
into the F[A]
object via pure
F[_]
converts the A => F[B]
morphism into the F[A] => F[B]
morphism via
flatMap
This is useful when you have a value of type F[A]
and
you want to apply a function of type A => F[B]
to it,
resulting in a value of type F[B]
.