What is the purpose of "do!" notation in F#?

10,265

Solution 1

F# computation expressions (a.k.a. "workflows") use the syntax

builder { expression }

where expression can contain special constructs including the various "bang" keywords like let! and do!. Like LINQ in C# or VB, F# computation expressions are just a syntactic sugar (that desugars into method calls on the builder).

One of the most common types of computation expression is async, as described here.

In this particular example, the async is being used along with Async.Sleep to temporarily get off the UI thread, to give the UI a chance to redraw, react to mouse events, etc. This general technique is described more here.

Solution 2

I'll only add that the do! notation doesn't have to be explicitly supported by the computation expression, because the same thing can be written using let! like this:

do! foo()       // Using do!
let! _ = foo()  // Equivalent using let!

In general let! us used when you have some function implemented using computation expressions and you want to call it from another computation expression of the same type. This means, that it is used for composing computation expressions. For async this composition means that you have a non-blocking asynchronous code and call it from another asynchronous workflow in some special way to make the call asynchronous.

The let! keyword allows you to do this and get some value as the result, while do! is a shortcut that you can use if the computation doesn't return anything.

A chapter from Real-world Functional Programming that discusses computation expressions (and also sequence expressions) is available as a free sample, so if you want to read a more detailed tutorial about computation expressions this may be a good source of infromation:

BTW: It should be possible to write the sample code in your question in a nicer way using the AwaitEvent primitive like this:

async { 
  let! _ = this.Loaded |> Async.AwaitEvent 
  do! Async.Sleep 200 
  for cmd in theDrawing do 
     do! this.Execute(cmd)  } |> Async.StartImmediate  

This means the same thing - it first waits until the Loaded event occurs, then it waits 200ms and then it does the rest of the work. This waiting is special (that's why we use let!/do!, because it doesn't block the thread while waiting).

Solution 3

In you case it is running the sleep expression asynchronously so the thread can do something useful rather than blocking.

In general, let!, use!, yield! and do! do the "special" processing of the containing computation expressions (whatever that is, async in this case). E.g. in a seq { ... } using yield! allows a sub-sequence to be merged into the output rather than being returned as a single object.

Share:
10,265

Related videos on Youtube

Max Galkin
Author by

Max Galkin

Blog: http://yacoder.guru/blog/ Twitter: @yacoder My CV: http://careers.stackoverflow.com/yacoder

Updated on November 03, 2020

Comments

  • Max Galkin
    Max Galkin over 3 years

    I'm a beginner in F#, so it's a simple question and maybe a duplicate, but I couldn't find the answer anywhere...

    I'm reading this LOGO DSL implementation and I don't understand, what is the meaning of the "do!" notation in here:

        this.Loaded.Add (fun _ ->
            async {
                do! Async.Sleep 200
                for cmd in theDrawing do
                    do! this.Execute(cmd)
            } |> Async.StartImmediate 
        )
    

    Can you help?

  • Max Galkin
    Max Galkin about 14 years
    Is there a name for this notation? Where to read more about it?
  • Prakash
    Prakash about 14 years
    "computation expressions" or "workflows"; an old (somewhat outdated) explanation is here: blogs.msdn.com/dsyme/archive/2007/09/22/…
  • Tomas Petricek
    Tomas Petricek about 14 years
    A chapter from Real-world Functional Programming that discusses computation expressions (and also sequence expressions) is available as a free sample chapter: manning.com/petricek/SampleChapter12.pdf

Related