The third monad law declares that the following identity must hold for a monad `M`, where `a:M<A>`, `f: A -> M<B>`, and `g: B -> M<C>`:

``````(a >>=- f) >>=- g   ==   a >>=- { b in f(x) >>=- g }
``````

To motivate this, we first want to show that the snippet below is a form of the left-hand-side of the identity:

``````// Form 1
let val = for {
b <- for {
ignore <- doSomething()
b1 <- doSomething()
} yield {
b1
}
c <- process(b) // process(val:Int?) -> Int?
} yield {
c
}
``````

Then we want to show that Form 2 below is a form of the right-hand-side:

``````// Form 2
let val = for {
ignore <- doSomething()
b <- doSomething()
c <- process(b) // process(val:Int?) -> Int?
} yield {
c
}
``````

Intuitively, these two snippets should do the same thing, which is the impetus for enshrining the behavior in a law.

• • • • •

Remembering that the right-hand side of a `<-` assignment is monadic, we can write Form 1 as:

``````// Form 1
let optB = doSomething() >>=- { ignore in
doSomething() >>=- { b in
lift(b)
}

let val = optB >>=- { b in
process(b) >>= { c in {
lift( c)
}
}
``````

Clearly, we can rewrite the snippet like this:

``````// Form 1
let val = doSomething() >>=- { ignore in
doSomething() >>=- lift
} >>=- { b in
process(b) >>=- lift
}
``````

Notice, incidentally, that nested for-comprehensions are the equivalent of chained `>>=-` calls. Using the second monad law (see, it’s useful), we can simplify it as:

``````// Form 1
let val =  doSomething() >>=- { ignore in
doSomething()
} >>=- { b in
process(b)
}
``````

Now let’s simplify by introducing the definition of
`doSomethingWhileIgnoring`:

``````func doSomethingWhileIgnoring(ignored:Int) -> Int? {
return doSomething()
}
``````

This takes us to the final form, with added parentheses to emphasize that `>>=-` is a left-associative operator.

``````// Form 1
let val = (doSomething() >>=- doSomethingWhileIgnoring) >>=- process
``````

• • • • •

For the second snippet, we’re going to work backwards. This means I’m going to start with what I already know I’m trying to get to, and I’m going to show you that it’s equivalent to Form 2. This is just as valid as going from Form 2 to the final result, but it’s easier to follow. What I want to show is that this snippet is the same as Form 2:

``````// Form 2 candidate
let val = doSomething() >>=- { ignore in
doSomethingWhileIgnoring(ignore) >>=- process
}
``````

So let’s get to substituting:

``````// Form 2 candidate
let val = doSomething() >>=- { ignore in
{ _ in doSomething() }(ignore) >>=- { b in
process(b)
}
}
``````

And now, using the second law, but in reverse, we have:

``````// Form 2 candidate
let val = doSomething() >>=- { ignore in
{ _ in doSomething() }(ignore) >>=- { b in
process(b) >>=- { c in
lift(c)
}
}
}
``````

Finally, it’s pretty clear that the second line is an unnecessary wrapper, and that we can write it as:

``````// Form 2 candidate
let val =
doSomething() >>=- { ignore in
doSomething() >>=- { b in
process(b) >>=- { c in
lift(c)
}
}
}
``````

But this is precisely the `>>=-` version of Form 2.

• • • • •

Again, remember that this appendix is not proving the law, but instead showing how it naturally comes out of expecting intuitive semantics from for-comprehensions. In the context of monads, “law” doesn’t mean something observed to be true, but rather a prescribed rule that a type must follow in order to be called a monad.