konnte keine for-Schleife im go-Block von core.async verwenden?

8

Ich bin neu in clojure core.async-Bibliothek, und ich versuche es durch Experimente zu verstehen.

Aber als ich es versuchte:

%Vor%

es gibt mir eine sehr seltsame Ausnahme:

%Vor%

und ich habe einen anderen Code ausprobiert:

%Vor%

Es gibt keine Compiler-Ausnahme.

Ich bin total verwirrt. Was ist passiert?

    
xudifsd 25.09.2014, 14:17
quelle

1 Antwort

16

Also stoppt der Clojure-Go-Block die Translation an Funktionsgrenzen aus vielen Gründen, aber die größte ist die Einfachheit. Dies wird am häufigsten bei der Konstruktion eines Lazy Seq gesehen:

%Vor%

Wird in etwa wie folgt kompiliert:

%Vor%

Lasst uns jetzt schnell darüber nachdenken ... was sollte das zurückgeben? Angenommen, was Sie wahrscheinlich wollten, war ein Lazy Seq mit dem Wert aus c, aber die <! muss den verbleibenden Code der Funktion in einen Callback übersetzen, aber LazySeq erwartet, dass die Funktion synchron ist. Um diese Einschränkung herum gibt es keinen Weg.

Also zurück zu deiner Frage, wenn du Makro% for erweiterst, wirst du sehen, dass es keine Schleife gibt, stattdessen expandiert es in eine Menge Code, der schließlich lazy-seq aufruft und so funktionieren Park-Ops nicht der Körper. doseq (und dotimes ) werden jedoch von loop / recur unterstützt und so werden diese vollkommen in Ordnung sein.

Es gibt noch ein paar andere Orte, an denen Sie stolpern könnten, wenn Sie with-bindings als Beispiel betrachten. Grundsätzlich, wenn ein Makro Ihre core.async Park-Operationen in eine verschachtelte Funktion hält, erhalten Sie diesen Fehler.

Mein Vorschlag ist dann, den Körper deiner Go-Blöcke so einfach wie möglich zu halten. Schreibe reine Funktionen und behandle dann den Körper von go-Blöcken als Orte, an denen IO ausgeführt werden soll.

------------ BEARBEITEN -------------

Mit stops translation an Funktionsgrenzen, ich meine das: Der go-Block nimmt seinen Körper und übersetzt ihn in eine Zustandsmaschine. Jeder Aufruf von <! >! oder alts! (und einige andere) werden als Zustandsautomatenübergänge betrachtet, bei denen die Ausführung des Blocks angehalten werden kann. An jedem dieser Punkte wird die Maschine in einen Rückruf umgewandelt und an den Kanal angeschlossen. Wenn dieses Makro eine fn -Form erreicht, hört es auf zu übersetzen. Sie können also nur <! innerhalb eines Go-Blocks aufrufen, nicht innerhalb einer Funktion innerhalb eines Codeblocks.

Dies ist Teil der Magie von core.async. Ohne das go-Makro würde core.async-Code in anderen Sprachen wie Rückruf-Hölle aussehen.

    
Timothy Baldridge 25.09.2014, 15:17
quelle

Tags und Links