2012-03-28 4 views
4

Gibt es eine Funktion in clojure, die prüft, ob Daten einen faulen Teil enthalten?Sehen Sie, ob ein Teil der Daten in clojure faul ist

Hintergrund:

Ich bin ein kleiner Server in clojure Gebäude. Jede Verbindung hat einen Status, einen Eingangsstrom und einen Ausgangsstrom.

Der Server liest ein Byte aus einem Eingangsstrom und ruft basierend auf dem Wert eine von mehreren Funktionen auf (mit dem Status und dem Eingangs- und Ausgangsstrom) als Parameter). Die Funktionen können entscheiden, mehr aus dem Eingabestream zu lesen, eine Antwort auf den Ausgabestream zu schreiben und einen Status zurückzugeben. Dieser Teil wird wiederholt.

Dies funktioniert alles gut, solange der Zustand keine faulen Teile enthält. Wenn es im Zustand einen etwas trägen Teil gibt, kann es, wenn es (später während einer anderen Funktion) ausgewertet wird, beginnen, aus dem Eingangsstrom zu lesen und in den Ausgangsstrom zu schreiben.

Also im Grunde möchte ich eine Post-Bedingung für alle diese Funktionen hinzufügen, die besagt, dass kein Teil des zurückgegebenen Zustand möglicherweise faul sein. Gibt es eine Funktion, die nach Lazy-Sequenzen sucht? Ich denke, es wäre leicht zu überprüfen, ob der Zustand selbst eine träge Sequenz ist, aber ich möchte zum Beispiel prüfen, ob der Zustand einen Vektor hat, der eine Hash-Map enthält, deren Werte faul sind.

Antwort

3

ist es einfacher, um sicherzustellen, dass sie nicht faul ist durch Auswertung zwingt mit doall

Ich hatte dieses Problem in einem Stream-Verarbeitung Krypto App ein paar Jahre zurück und versucht, mehrere Möglichkeiten, bis ich endlich meinen faulen Seite akzeptiert und Die Eingabe-Streams wurden in einer verzögerten Sequenz verpackt, die in Eingabe-Streams geschlossen wurde, wenn keine Daten mehr verfügbar waren. effektiv Trennung der Sorge für das Schließen der Ströme von der Sorge darüber, was die Ströme enthalten. Der Status, den Sie verfolgen, klingt etwas ausgefeilter als offen oder geschlossen, obwohl Sie in der Lage sein könnten, ihn auf ähnliche Weise zu trennen.

+0

Doall funktioniert nicht rekursiv leider: '(count (doall [1 2 3 4 (Bereich)])) wird 5, und nicht Stack/Heapoverflow. – Claude

+0

Ah, und im zweiten Teil: Wrapping der Eingangsstrom in einer Lazy-Sequenz ist etwas, was ich dachte, und funktioniert (obwohl Sie Sachen wie Java DataInputStream verlieren).Mit dem Outputstream funktioniert das allerdings nicht, das ist der eine Ort, an dem man eigentlich den Nebeneffekt braucht. – Claude

+0

(count (map doall (filter seq? [1 2 3 4 (Bereich)]))) –

1

Sie könnten sicherlich die Auswertung mit doall erzwingen, wie Arther weise empfiehlt.

Allerdings würde ich stattdessen Refactoring empfehlen, um das eigentliche Problem zu lösen, das ist, dass Ihre Handler-Funktion Nebenwirkungen hat (Lesen von Eingabe, Schreiben zur Ausgabe).

Sie stattdessen diese in eine reine Funktion drehen könnte, wenn Sie das tun folgende:

  • Wickeln Sie den Eingangsstrom als faul Sequenz
  • Verwendung [Eingabe-Sequenz Zustand] als Eingabe für Ihre Handler-Funktion
  • Verwendung [list-of-schreibt neue staatliche Rest-of-Input-Sequenz] als Ausgabe, wo Liste schreibt, was anschließend in den Ausgabestream
  • geschrieben werden muss, ist

Wenn Sie das tun, Ihre Die Handler-Funktion ist rein. Sie müssen sie nur in einer einfachen Schleife ausführen (die Liste der Schreibvorgänge wird bei jeder Iteration an den Ausgabestream gesendet), bis alle Eingaben verbraucht sind und/oder eine andere Beendigungsbedingung erreicht ist.

+0

Alles, was faul berührt, wird faul :) – Ankur

+0

@Ankur - das ist wahr (vorausgesetzt, du erzwingst keine Bewertung), obwohl ich denke, der wichtigste Punkt ist, dass wenn du bleibst zu reinen Funktionen zählt Faulheit nie. – mikera

+0

Ich habe diesen Vorschlag über den letzten Tag oder so viele Gedanken gemacht. Auf der einen Seite mag ich die reine Funktion. Das Arbeiten mit Sequenzen entfernt jedoch (in meiner Vorstellung) die Reinheit des Codes. Wenn ich einen Stream habe, von dem ich zuerst ein langes (a), dann ein Byte (b) und dann (b) viele Ints lesen muss, wäre es leicht zu machen (und für jeden, der den Code liest, einfach zu verstehen) '(lassen Sie [a (.readInt i) b (.readByte i) c (wiederholt b # (. readInt i))] ...). Wie würde man das sauber mit einer Sequenz machen ... – Claude

Verwandte Themen