Дизайн языка С# всегда (исторически) был направлен на решение конкретных проблем, а затем на поиск для решения основных проблем: см. http://blogs.msdn.com/b/ericlippert/archive/2009/07/09/iterator-blocks-part-one.aspx для "IEnumerable vs. coroutines":
Мы могли бы сделать это гораздо более общим. Наши итераторные блоки можно рассматривать как слабый вид сопрограммы. Мы могли бы выбрали реализацию полных сопрограмм и просто сделали блок итераторов специальным случаем сопрограмм. И, конечно, сопрограммы, в свою очередь, менее общие, чем первоклассные продолжения; мы могли бы реализовывать продолжения, реализовывать сопрограммы с точки зрения продолжений и итераторы с точки зрения сопрограмм.
или http://blogs.msdn.com/b/wesdyer/archive/2008/01/11/the-marvels-of-monads.aspx для SelectMany как суррогат для (некоторых) Монадов:
Система типа С# недостаточно эффективна для создания обобщенной абстракции для монад, которая была основным мотиватором для создания методов расширения и "шаблона запроса"
Я не хочу спрашивать, почему так было (много хороших ответов уже даны, особенно в блоге Eric, которые могут применяться ко всем этим проектным решениям: от производительности до повышенной сложности, как для компилятора, так и для программиста).
То, что я пытаюсь понять, - это то, к чему относится "общая конструкция", к которой относятся ключевые слова async/await (моя лучшая догадка - продолжение монады - в конце концов, асинхронная реализация F # реализована с использованием рабочих процессов, что, на мой взгляд, является продолжением монады), и как они относятся к нему (как они отличаются друг от друга, чего нет?), почему есть пробел, если таковые имеются?)
Я ищу ответ, похожий на статью, связанную с Eric Lippert, связанную с ней, но связанную с async/await вместо IEnumerable/yield.
Изменить: помимо отличных ответов, некоторые полезные ссылки на связанные вопросы и сообщения в блоге, где это предлагается, я редактирую свой вопрос, чтобы перечислить их: