Good tutorial choices; they're very well-written. I haven't used F# much, but here's my take (call me out on any mistakes in my understanding):

`async` being just a particular instance of a class of user/library-defined "computation expression" has a lot of good things going for it. This setup provides an alternative to nested lambda expressions that's more readable in some cases. And it's far more future-proof than C#'s approach.

There was one thing I didn't like about monadic F#: it's hard to read without being intimately familiar with the "workflow" you are using (e.g. `async`). If I see a `for..do` expression inside an `async` block, I don't know whether `async` has overridden that syntax unless I open up the `async`'s documentation. It seems this is easily side-stepped by using explicit syntax (e.g. `for!` instead of `for`), which makes me wonder why the F# designers made some of the syntax overrides stand out (`let!` and `do!`), but not others (`return` and `while..do`).

Finally, I wonder what happens if you nest computation expressions:

  async {
    query {
      /* Code for an asynchronous query. */
    }
  }

My guess it that the inner workflow (`query`) transforms the code inside it, then passes the result to the outer workflow, which then transforms it further. This could get confusing quickly, but I suppose you'd only write something like this if it was the best way to express your intent, which means the alternatives were *more* confusing.

Reply via email to