IOis two free monads glued together with an interpreter that can sequence back and forth between them.
Contis itself a free monad for a coalgebra, while
Freeis obviously… uh,
Free, and we instantiate it with a trivial algebra
raiseErroris hard with the above)
Contis so bizarre
ContTis even more bizarre
I would start looking at the runloop from these 3 points:
IOit's a tree that gets translated, and each node in the tree represent a fundamental concept (so you have
case class State(current: IO[Any], stack: List[Any => IO[Any]]. Each iteration pattern matches on
current, does some stuff, and keeps going by taking the next off the stack.
case class Async(f: (Either[Throwable, A] => Unit) => Unit) extends IO[A]. The key point is that
Asyncdoes not introduce any asynchrony, it just wraps something that can already do asynchrony by itself. It's kinda funny in that
Asyncdoes most of the work for the "complex" stuff, but actually the only thing it does is passing a function to another function.
I can expand and unpack some of this if needed