Yet another tutorial on Monads(,Monoids, and Functors with Scala)

Upfront, this post is really shallow, only defining terms. It does not go into the application and consequences of these objects. But these notes are useful to me because it explains these terms directly involving Category Theory where necessary. It does not go into depths about how monads can convert imperative to functional code, or that the consequence monoid associativity is parallelism. Honestly, I feel the other tutorials already do a good job of that.

Monad in terms of monoids and functors

A monad can be described as 1 a monoid whose objects are functors 2 In Scala, an implementation of one of the minimal sets of monadic combinators, satisfying the laws of associativity and identity (Monad Laws)

Monoid

The following are two valid definitions of a monoid

  1. A category with exactly one object
  2. An algebra (recall algebra is just objects and operations) that consists of
    1. objects of some type A
    2. an associative binary operation, ie say op where op(op(x,y), z) = op(x, op(y, z)) and x,y,and z are of type A
    3. An identity or zero object where op(x,zero)= op(zero, x) = x

Remember, either definitions are valid. You do not need to know Category Theory to know what a monoid is.

In Scala, a monoid can be expressed with this trait

trait Monoid[A] {
  def op(a1: A, a2: A): A
  def zero: A
}

Examples of monoids include

  • type Bool, associative binary operation &&, id object true
  • type Bool, associative binary operation ||, id object false
  • type String, opn string concatenation +, id object empty string ""
  • type List, opn list concatenation +, id object empty list Nil

Functor

If A and B are categories, a functor from A to B is an assignment of

  • an object Φ(A) in B for every object A in A
  • an arrow Φ(f) : Φ(A) -> Φ(A’) in B for every arrow A -> A’ in A subject to the following equations:

In Scala, most objects with a map method are functors.

And finally, an example of a monoid whose objects are functors:

  • type A -> List[B], opn: List.flatMap eg val x: A -> List[B] = _.map(f) val y: B -> List[C] = _.map(g) val z: C -> List[D] = _.map(h) // op(op(x,y),z) = op(x,op(y,z)) x.flatMap(y).flatMap(z) == x.flatMap(a => y(a).flatMap(z)) , id object _.map(_=>_)

“Monad laws”, “Monoid laws”, “Monadic Combinators”

The associativity and identity laws are “Monad laws” also “Monoid laws”.

Let’s revisit the definition of a monad in Scala, an implementation of one of the minimal sets of monadic combinators, satisfying the laws of associativity and identity (Monad Laws).

Implementations of these minimal sets of monadic combinators satisfy the laws of associativity and identity.

  • unit and flatMap
  • unit and compose
  • unit, map, and join

where unit is the identity / zero object, and join has function signature
def join[A](mma: F[F[A]]): F[A]