I have used coroutines in almost every game I've made, but not stopped to think about how they really work.
Source for the below text: http://catlikecoding.com/unity/tutorials/constructing-a-fractal/
My own notes and additions are in bold/blue
What does yield do?
The yield statement is used by iterators to make life easy for them (this part could potentially be explained better. Iteration is the act of repeating a process. Usually, when people talk about working iteratively, they are talking about working, making a small change or fix, then continuing to work and repeating that process, as opposed to doing it all in one go and fixing everything at the end. In this case, I think the sentence is talking about iterative functions and loops.).
To make enumeration possible, you'd need to keep track of your progress. This involves some boilerplate code (boilerplate code refers to code that has to be included in lots of different sections without being changed eg declarations or the basic empty template in HTML) that is essentially always the same. What you'd really want is to just write something like return firstItem; return secondItem; until you are done. The yield statement allows you to do exactly that.
So whenever you're using yield, an enumerator object is created behind the scenes to take care of the tedious bits.
Alternate definition: 'The yield statement is a special kind of return, that ensures that the function will continue from the line after the yield statement next time it is called.'
How do coroutines work?
When you're creating a coroutine in Unity, what you're really doing is creating an iterator. When you pass it to the StartCoroutine method, it will get stored and gets asked for its next item every frame, until it is finished.
The yield statements produce (return) the items (actions?). The statements in between – the stuff that you want to happen – are side-effects of the iterator doing its job.
You can yield special things like WaitForSeconds to have more control over when your own code continues, but the overall approach is simply that of an iterator.
Alternate definition: 'A coroutine is like a function that has the ability to pause execution and return control to Unity but then to continue where it left off on the following frame.' (source)