Perhaps I need to clarify a little:
I did know about the Monad abstraction before “discovering” that page. And I agree totally with what you said about wanting HKTs and do-notation in Rust instead of the suggested ? operator.
However, the problem with the Haskel style do-notation is that it doesn’t mash well with imperative code.
The novelty with the async/await and coroutines AFAIU is that they provide a different kind of do-notation, that works better for imperative code.
The main difference is that in Haskel the do-notation is syntax sugar for wrapping a value (sort of) whereas the await operator provides unwrapping.
let’s look at a concrete example:
fn foo() -> Result<T, E> {
let x = try!( f1() );
let y = try!( f2() );
Ok( goo(x, y));
}
becomes a co-routine such as:
fn foo() -> Result<T, E> {
let x = await f1();
let y = await f2();
return goo(x, y);
}
This looks like the same semantics - the await introduces a suspension point. This means that if the result of say f1() isn’t “ready” the control returns to the caller in our case (like a more principled throw statement), similar to how try!() generates an early return for the error case. In contrast, the Haskel do-notation wraps the value in a closure. So this goes up the call stack whereas do-notation goes down the call stack.
Important thing to note about the proposed c++ design is that the compiler lowers the co-routine to a protocol defined by some known “trait” (concept) and that library writers can implement this trait for their types in order to plug into this mechanism. Honestly this is a very rustic approach - think lang-items and the Iterator trait for instance.