The three Monad laws may seem pretty abstract at first, but they're quite practical. Let's try to internalize the laws by running through two of Scala's most popular monads and making sure they adhere. We could use something like ScalaCheck to more rigorously check these laws, but the purpose of this post is to help internalize them, so we'll only be manually verifying them using our intuition.

Here are the laws, from Monad laws on HaskellWiki.

- Left identity:
`return a >>= f ≡ f a`

- Right identity:
`m >>= return ≡ m`

- Associativity:
`(m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)`

In Haskell, `return`

is used to "inject a value into the
monadic type". In Scala, we do this via constructors (unless you're using
Scalaz, in which case you probably already know everything this post has to
offer).

The `>>=`

operator in Haskell corresponds to Scala's
`flatMap`

method.

## List

The List Monad deals with the context of non-determinism—that is, it represents multiple values. When we run multiple lists through a sequence comprehension we end up with the all combinations of values from each list.

_10for (x <- List(1, 2, 3); y <- List('a', 'b', 'c')) yield (x, y)_10=> List((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c))

Now the laws. Let's setup two simple functions `f`

and `g`

, both of type `Int => List[Int]`

.

_10// Let f be a function that takes an Int and produces a List of its_10// neighboring Ints along with itself:_10val f: (Int => List[Int]) = x => List(x - 1, x, x + 1)_10_10// Let g be a function that takes an Int x_10// and produces a List containing +x and -x_10val g: (Int => List[Int]) = x => List(x, -x)

### Left identity

_10val a = 2_10val lhs = List(a).flatMap(f)_10=> List(1, 2, 3)_10_10val rhs = f(a)_10=> List(1, 2, 3)_10_10lhs == rhs_10=> true

### Right identity

_10val m = List(2)_10_10val lhs = m.flatMap(List(_))_10=> List(2)_10_10val rhs = m_10=> List(2)_10_10lhs == rhs_10=> true

### Associativity

_11val m = List(1, 2)_11_11val lhs = m.flatMap(f).flatMap(g)_11=> List(0, 0, 1, -1, 2, -2, 1, -1, 2, -2, 3, -3)_11// Sidenote: now do you see what is meant by non-determinism?_11_11val rhs = m.flatMap(x => f(x).flatMap(g))_11=> List(0, 0, 1, -1, 2, -2, 1, -1, 2, -2, 3, -3)_11_11lhs == rhs_11=> true

Looks good to me.

## Option

Let's create new test functions `f`

and `g`

of type `Int => Option[Int]`

. Given the type signature, it's natural to think
of `f`

and `g`

as *partial functions* that are only defined on certain inputs.

_10// If x is not less than 10, return 2x_10val f: (Int => Option[Int]) = x => if (x < 10) None else Some(x * 2)_10_10// If x is reater than 50, return x + 1_10val g: (Int => Option[Int]) = x => if (x > 50) Some(x + 1) else None

For the sake of testing our laws, the implementations of these functions really don't matter as long as the types line up.

### Left identity

_10val a = 30_10val lhs = Option(a).flatMap(f)_10=> Some(60)_10_10val rhs = f(a)_10=> Some(60)_10_10lhs == rhs_10=> true

### Right identity

_10val m = Option(30)_10_10val lhs = m.flatMap(Option(_))_10=> Some(30)_10_10val rhs = m_10=> Some(30)_10_10lhs == rhs_10=> true

### Associativity

_10val m = Option(30)_10_10val lhs = m.flatMap(f).flatMap(g)_10=> Some(61)_10_10val rhs = m.flatMap(x => f(x).flatMap(g))_10=> Some(61)_10_10lhs == rhs_10=> true

## The end

I hope this post helped you internalize the Monad laws. If you need more
practice, continue this exercise in your REPL for the `Try`

and `Either`

monads, or better yet: create your own Monad and
verify that it obeys the laws!