Ich versuche, einen Conduit zu erstellen, der mehrere Eingabeströme konsumieren kann. Ich muss in der Lage sein, auf den einen oder den anderen der Eingabeströme in keiner bestimmten Reihenfolge (z. B. nicht alternierend) zu warten, was zip unbrauchbar macht. Hier läuft nichts parallel oder nicht-deterministisch ab: Ich warte auf den einen oder den anderen Strom. Ich möchte in der Lage sein, Code ähnlich dem folgenden zu schreiben (wobei awaitA
und awaitB
auf den ersten bzw. zweiten Eingabestrom warten):
Die beste Lösung, die ich habe, ist, die innere Monade zu einem anderen Kanal zu machen, z. B.
%Vor%Was dann erlaubt
%Vor%Und das funktioniert meistens. Unglücklicherweise scheint es sehr schwierig zu sein, mit der inneren Leitung zu verschmelzen, bevor die äußere Leitung vollständig verbunden ist. Das erste, was ich versuchte, war:
%Vor% Aber das funktioniert nicht, zumindest wenn x
statusbehaftet ist, da (x =$=)
mehrmals ausgeführt wird und jedesmal x
neu gestartet wird.
Gibt es irgendeinen Weg, fuseInner zu schreiben, kurz vor dem Einbruch ins Innere des Conduits (was aussieht, als wäre es ziemlich chaotisch)? Gibt es eine bessere Möglichkeit, mehrere Eingabeströme zu verarbeiten? Bin ich weit darüber hinaus, wofür der Conduit gedacht war?
Danke!
Wenn Sie zwei IO
-generierte Streams kombinieren wollen, ist Gabriels Kommentar die Lösung.
Ansonsten können Sie nicht auf beide Streams warten, welcher zuerst einen Wert erzeugt. Conduits sind single-threaded und deterministisch - es verarbeitet jeweils nur eine Pipe. Sie können jedoch eine Funktion erstellen, die zwei Streams verschachtelt und ihnen die Entscheidung zum Umschalten zulässt:
%Vor% Es verarbeitet eine Quelle, bis es Nothing
zurückgibt, wechselt dann zu einer anderen usw. Wenn eine Quelle beendet ist, wird die andere bis zum Ende verarbeitet.
Als Beispiel können wir zwei Listen kombinieren und verschachteln:
%Vor% Wenn Sie mehrere Quellen benötigen, könnte merge
an etwas wie
, die durch die angegebene Liste der Quellen durchlaufen würde, bis alle fertig sind.
Dieses kann durch Eintauchen in das Innere des Conduits erreicht werden. Ich wollte das vermeiden, weil es extrem unordentlich aussah. Basierend auf den Antworten hier klingt es wie es ist kein Weg um es (aber ich würde wirklich eine sauberere Lösung schätzen).
Die Hauptschwierigkeit ist, dass (x =$=)
eine reine Funktion ist, aber um transPipe
die richtige Antwort geben zu können, braucht es eine Art statusbehafteter, funktionsähnlicher Sachverhalt:
Schritt StatefulMorph m n
nimmt einen Wert in m
und gibt, in n
, sowohl diesen Wert als auch die nächste StatefulMorph
zurück, die verwendet werden sollte, um den nächsten m
-Wert zu transformieren. Der letzte StatefulMorph
sollte abgeschlossen werden (was im Fall von "stateful (x =$=)
" den x
Conduit abschließt.
Die Conduit-Fusion kann als StatefulMorph
implementiert werden, wobei der Code für pipeL
mit geringfügigen Änderungen verwendet wird. Die Signatur ist:
Ich brauche auch eine Ersetzung für transPipe
(ein Sonderfall von hoist
), die StatefulMorph
Werte anstelle von Funktionen verwendet.
Eine StatefulHoist
Instanz für ConduitM i o
kann mit dem Code für transPipe
mit einigen kleineren Änderungen geschrieben werden.
fuseInner
ist dann einfach zu implementieren.
Ich habe hier eine ausführlichere Erklärung geschrieben und den vollständigen Code hier . Wenn jemand eine sauberere Lösung finden kann oder eine, die die Conduit public API verwendet, poste sie bitte.
Danke für alle Vorschläge und Anregungen!