2012-05-31 30 views
9

Ich habe eine einfache Aufgabe - lesen Sie eine Reihe von Zeilen aus einer Datei und machen Sie etwas mit jedem von ihnen. Außer der ersten - das sind einige Überschriften, die ignoriert werden müssen.Wie wird die Funktion der Leitungsabzweigung in einer Pipeline verwendet?

Also dachte ich, ich würde Conduits ausprobieren.

printFile src = runResourceT $ CB.sourceFile src =$= 
    CT.decode CT.utf8 =$= CT.lines =$= CL.mapM_ putStrLn 

Kühl.

So, jetzt möchte ich nur aus der ersten Linie fallen ... und es scheint, dass eine Funktion zu sein -

printFile src = runResourceT $ CB.sourceFile src =$= 
    CT.decode CT.utf8 =$= CT.lines =$= drop 1 =$= CL.mapM_ putStrLn 

Hmm - aber jetzt merke ich, Drop-Typ hat Unterschrift Sink a m(). Jemand schlug mir vor, dass ich das Monade Beispiel für Rohre und Verwendung Drop verwenden kann, um effekt einige Elemente fallen - so habe ich versucht, dies:

drop' :: Int -> Pipe a a m() 
drop' n = do 
    CL.drop n 
    x <- await 
    case x of 
    Just v -> yield v 
    Nothing -> return() 

Welche nicht überprüft nicht geben, weil das Monade Beispiel für Rohre nur auf Rohre gilt vom gleichen Typ - Sinks haben Void als Output, also kann ich es nicht so benutzen.

Ich warf einen kurzen Blick auf Rohre und Rohre-Kern und ich bemerke, dass Pipes-Kern hat die Funktion, wie ich es erwartet hatte, wo Pipes eine minimale Bibliothek ist, aber die Dokumentation zeigt, wie es implementiert werden würde.

So verwirrt bin ich - vielleicht ist es ein Schlüsselkonzept fehlt mir .. Ich sah die Funktion

sequence :: Sink input m output -> Conduit input m output 

Aber das scheint nicht die richtige Idee zu sein, da der Ausgangswert (

)
CL.sequence (CL.drop 1) :: Conduit a m()  

ich werde wahrscheinlich und einfach wieder faul-io verwenden, wie ich jedes Streaming brauche nicht wirklich - aber ich wäre daran interessiert, die richtige Art und Weise zu sehen, es zu tun.

Antwort

6

Erstens ist die einfache Antwort:

... =$= CT.lines =$= (CL.drop 1 >> CL.mapM_ putStrLn) 

Die längere Erklärung: Es gibt wirklich zwei verschiedene Möglichkeiten, wie Sie drop implementieren können. In jedem Fall werden zuerst n Elemente aus dem Eingang gelöscht. Es gibt zwei Möglichkeiten, zu wissen, was es tut nächste:

  • sagt es
  • beginnen alle verbleibenden Elemente aus dem Eingangsstrom ist

Der frühere Verhalten getan ausgibt, was ein Sink funktionieren würde (und was unser drop tatsächlich tut) während letzteres das Verhalten eines Conduit ist. Sie können die letztere aus der früheren durch monadische Zusammensetzung in der Tat erzeugen:

dropConduit n = CL.drop n >> CL.map id 

Dann können Sie dropConduit verwenden, wie Sie am Anfang beschreiben. Dies ist ein guter Weg, um den Unterschied zwischen monadischer Zusammensetzung und Verschmelzung aufzuzeigen; Erstere erlaubt es, dass zwei Funktionen am selben Eingangsstrom arbeiten, während der zweite eine Funktion ermöglicht, einen Strom an den anderen zu leiten.

Ich habe keinen Benchmark, aber ich bin ziemlich sicher, dass monadische Zusammensetzung ein bisschen effizienter sein wird.

+0

Hmm - die einfache Antwort funktioniert gut, danke. dropConduit ist 'Monad m => Int -> Pfeifen Void Void m()' was ich denke, macht es ziemlich schwer zu verwenden, für alles, was ich denke? – Oliver

+0

Entschuldigung, ich arbeite an einer anderen Version der Codebasis, wo das nicht gelten würde. In Conduit 0.4 müssten Sie "sinkToPipe (CL.drop n) >> CL.map id" haben. Das Problem ist, dass die Typen in Data.Conduit.List zu restriktiv sind. Conduit 0.5 wird sie entspannen. –

+0

Ahh - Prost. Das macht Sinn. – Oliver

Verwandte Themen