27 Stimmen

Was ist der Zweck der "do!"-Notation in F#?

Ich bin ein Anfänger in F#, so dass es eine einfache Frage und vielleicht ein Duplikat ist, aber ich konnte die Antwort nirgends finden ...

Ich lese gerade diese LOGO DSL-Implementierung und ich verstehe nicht, was der "do!"-Schriftzug hier zu bedeuten hat:

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

Können Sie helfen?

25voto

Tomas Petricek Punkte 233658

Ich möchte nur hinzufügen, dass die do! Notation muss nicht explizit durch den Berechnungsausdruck unterstützt werden, denn dasselbe kann auch mit let! wie diese:

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

Im Allgemeinen let! wird verwendet, wenn Sie eine Funktion mit Hilfe von Berechnungsausdrücken implementiert haben und diese von einem anderen Berechnungsausdruck desselben Typs aus aufrufen möchten. Das bedeutet, dass sie zum Zusammensetzen von Berechnungsausdrücken verwendet wird. Für async este Zusammensetzung bedeutet, dass Sie einen nicht-blockierenden asynchronen Code haben und ihn von einem anderen asynchronen Workflow aus auf eine spezielle Weise aufrufen, um den Aufruf asynchron zu machen.

En let! Schlüsselwort können Sie dies tun und einen Wert als Ergebnis erhalten, während do! ist eine Abkürzung, die Sie verwenden können, wenn die Berechnung kein Ergebnis liefert.

Ein Kapitel aus Real-world Functional Programming, das Berechnungsausdrücke (und auch Sequenzausdrücke) behandelt, ist als kostenloses Beispiel verfügbar. Wenn Sie also ein ausführlicheres Tutorial über Berechnungsausdrücke kann dies eine gute Informationsquelle sein:

BTW: Es sollte möglich sein, den Beispielcode in Ihrer Frage auf eine schönere Weise zu schreiben, indem man die AwaitEvent primitiv wie diese:

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

Das bedeutet dasselbe - es wird zunächst gewartet, bis die Loaded Ereignis eintritt, wartet es 200ms und erledigt dann den Rest der Arbeit. Diese Warten ist speziell (deshalb verwenden wir let! / do! weil es den Thread während des Wartens nicht blockiert).

12voto

Brian Punkte 115257

F# Berechnungsausdrücke (auch bekannt als "Workflows") verwenden die Syntax

builder { expression }

donde expression kann spezielle Konstrukte enthalten, darunter die verschiedenen "bang"-Schlüsselwörter wie let! y do! . Wie LINQ in C# oder VB sind F#-Berechnungsausdrücke nur ein syntaktischer Zucker (der sich in Methodenaufrufe auf der builder ).

Eine der häufigsten Arten von Berechnungsausdrücken ist async wie beschrieben aquí .

In diesem speziellen Beispiel ist die async wird verwendet zusammen mit Async.Sleep um den UI-Thread vorübergehend zu verlassen, damit die Benutzeroberfläche die Möglichkeit hat, sich neu zu zeichnen, auf Mausereignisse zu reagieren, usw. Diese allgemeine Technik wird näher beschrieben aquí .

4voto

Richard Punkte 103159

In Ihrem Fall wird der sleep-Ausdruck asynchron ausgeführt, so dass der Thread etwas Sinnvolles tun kann, anstatt zu blockieren.

Generell, let! , use! , yield! y do! die "spezielle" Verarbeitung der enthaltenen Berechnungsausdrücke (was auch immer das ist), async in diesem Fall). Z. B. in einer seq { ... } mit yield! ermöglicht es, eine Teilsequenz in die Ausgabe einzubinden, anstatt sie als einzelnes Objekt zurückzugeben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X