A monoid has two components:
"make an instance from nothing"
0
(Unit => Int
)""
(Unit => String
)Nil
(Unit => List[_]
)
- "combine two instances"
(T,T) => T
(summation, reduction)
A monad has two components:
T => F[T]
:
- "make an F from thin air"
(F[A], A => F[B]) => F[B]
At first, that type signature makes people think of:
(F[A], A => F[B]) => F[F[B]]
Note the doubly nested F
in the result; this is what you'd naively get from a Functor map
.
Each Monad's special essence is: how does it flatten (i.e. F[F[B]] => F[B]
)?
List
: make one list by concatenating all elemsFuture
: keep kicking the "deferred" can down the roadOption
: each level of nesting can always short-circuit the whole thing toNone
- etc.
Turning F[F[B]]
into F[B]
is like combining two [nested levels of F[_]
] into one, which sounds a lot like monoidal combine
above.
So a monad is like a higher-level monoid in some way:
id
→bind
combine
→flatMap
Monad.bind
actually goes from Id[T] => F[T]
- it's a "natural transformation":
Id ~> F
- it creates an
F
from "nothing" (Id
)
Monad.bind
actually goes from F⊙F [T] => F[T]
- it's a "natural transformation
(F,F) -> F
- it combines two
F
s into one
👋👋👋👋👋