2016-06-21 12 views
1

Wie hängt man eine ResumableSource an eine andere an, wenn sie nicht explizit eine Instanz von Monad ist? Hier ist ein Spielzeugbeispiel unten - a hat Monad Constraint, während b es nicht hat. So können wir a's hängen, aber nicht b's:Eine resumableSource an eine andere anhängen

Prelude> import Data.Conduit 
Prelude Data.Conduit> import Data.ByteString as BS 
Prelude Data.Conduit BS> import Control.Monad.Trans.Resource 
Prelude Data.Conduit BS Control.Monad.Trans.Resource> let a = newResumableSource (yield (BS.pack [5])) -- this one has monad constraint 
Prelude Data.Conduit BS Control.Monad.Trans.Resource> :t a 
a :: Monad m => ResumableSource m ByteString 
Prelude Data.Conduit BS Control.Monad.Trans.Resource> :t a >> a 
a >> a 
    :: (Monad m, Monad (ResumableSource m)) => 
    ResumableSource m ByteString 
Prelude Data.Conduit BS Control.Monad.Trans.Resource> let b = undefined :: ResumableSource (ResourceT IO) ByteString 
Prelude Data.Conduit BS Control.Monad.Trans.Resource> :t b >> b 

<interactive>:1:3: 
    No instance for (Monad (ResumableSource (ResourceT IO))) 
     arising from a use of ‘>>’ 
    In the expression: b >> b 

Der Grund, warum ich es bin zu fragen, weil ich ein HTTP ResumableSource mit gleichem Typ wie b oben habe, auf die ich mag den Content-Length Zierer, bevor es Verfütterung an sinken. Derzeit sieht es wie folgt aus:

responseBody rsp $$+- sink 

Was ich zu so etwas ändern mögen:

((newResumableSource (yield content-len)) >> (responseBody rsp)) $$+- sink 
+0

Beachten Sie sorgfältig die abgeleitete Art von 'a >> a :: (Monad m, Monad (wiederaufladbare Quelle m)) => ResumableSource m ByteString'. Wenn Sie 'm' instanziieren, sucht der Elaborator nach einer Instanz von' Monad (ResumableSource m) '. Da 'ResumableSource' keine 'Monad'-Instanz hat, schlägt die Typprüfung fehl. Mit anderen Worten, es gibt keine Möglichkeit, _a_a_a_zu verwenden. –

+0

ha, ja, guter Punkt. Frage mich, ob ich einfach einen Ertrag erzielen könnte, ohne dass die Senke nach der ersten Quelle beendet wird? Wie 'Ausbeute Inhalt-len $$ sinken; (responseBody rsp)) $$ + - sinken. – Sal

Antwort

0

Eine gute Möglichkeit, erste Nachricht zu ResumableSource vorangestellt scheint ein conduit welche Erträge zu bedienen zu sein diese erste Nachricht und wird dann ein Durchreichen. Hier habe ich den Code aus map Leitung entlehnt, um eine solche Leitung zu erstellen:

passThruWInit :: Monad m => BS.ByteString -> C.Conduit BS.ByteString m BS.ByteString 
passThruWInit initMsg = do 
    C.yield initMsg -- generate initial message first 
    C.awaitForever $ C.yield -- now pass-through conduit for all messages 

Jetzt haben wir responseBody rsp $$+- sink Code aktualisieren, um es fit zwischendurch:

responseBody rsp $=+ passThruWInit someInitMsg $$+- sink 

Das Nettoergebnis ist, dass someInitMsg ergab sich zuerst und dann responseBody Inhalt wird durchgestreamt. Auf diese Weise können wir dem wiederaufsetzbaren HTTP-Antworttext content-length und andere Metadaten voranstellen.

Verwandte Themen