Я только добавлю, что нотация do!
не должна явно поддерживаться выражением вычисления, потому что то же самое можно записать с использованием let!
, например так:
do! foo() // Using do!
let! _ = foo() // Equivalent using let!
Обычно let!
используется, когда у вас есть функция, реализованная с использованием выражений вычислений, и вы хотите вызывать ее из другого выражения вычислений того же типа. Это означает, что он используется для составления вычислительных выражений. Для async
эта композиция означает, что у вас есть неблокирующий асинхронный код и вы вызываете его из другого асинхронного рабочего процесса особым образом, чтобы сделать вызов асинхронным.
Ключевое слово let!
позволяет вам сделать это и получить какое-то значение в качестве результата, тогда как do!
- это ярлык, который вы можете использовать, если вычисление ничего не возвращает.
Глава из функционального программирования реального мира, в которой обсуждаются выражения вычислений (а также выражения последовательностей), доступна в качестве бесплатного примера, поэтому, если вы хотите прочитать более подробное руководство по выражениям вычислений , это может хороший источник информации:
Кстати: должна быть возможность написать пример кода в вашем вопросе лучше, используя примитив AwaitEvent
, подобный следующему:
async {
let! _ = this.Loaded |> Async.AwaitEvent
do! Async.Sleep 200
for cmd in theDrawing do
do! this.Execute(cmd) } |> Async.StartImmediate
Это означает то же самое - сначала он ждет, пока не произойдет событие Loaded
, затем он ждет 200 мс, а затем выполняет остальную работу. Это ожидание является особенным (поэтому мы используем let!
/ do!
, потому что оно не блокирует поток во время ожидания).