Si lo que desea es código, es la siguiente:
procFile' iFile oFile = fileDriver (joinI $
enumLinesBS ><>
mapChunks (map rstrip) $
I.mapM_ (B.appendFile oFile))
iFile
Comentario:
Este es un proceso de tres etapas: primero a transformar la corriente en bruto en una corriente de líneas, a continuación, aplicar su Funciona para convertir ese flujo de líneas, y finalmente usted consume el flujo. Como rstrip
se encuentra en la etapa intermedia, creará un transformador de flujo (Enumeratee).
Puede usar mapChunks
o convStream
, pero mapChunks
es más simple. La diferencia es que mapChunks
no le permite cruzar los límites de los fragmentos, mientras que convStream
es más general. Prefiero convStream
porque no expone ninguna de las implementaciones subyacentes, pero si mapChunks
es suficiente, el código resultante suele ser más corto.
rstripE :: Monad m => Enumeratee [ByteString] [ByteString] m a
rstripE = mapChunks (map rstrip)
Nota extra map
en rstripE
. El flujo externo (que es la entrada a rstrip) tiene el tipo [ByteString]
, por lo que necesitamos asignarle rstrip
.
Para la comparación, esto es lo que se vería si se aplican con convStream:
rstripE' :: Enumeratee [ByteString] [ByteString] m a
rstripE' = convStream $ do
mLine <- I.peek
maybe (return B.empty) (\line -> I.drop 1 >> return (rstrip line)) mLine
Esto es más larga, y es menos eficiente, ya que sólo se aplicará la función rstrip a una línea a la vez, incluso aunque hay más líneas disponibles. Es posible trabajar en todo el trozo disponibles en la actualidad, que está más cerca de la versión mapChunks
:
rstripE'2 :: Enumeratee [ByteString] [ByteString] m a
rstripE'2 = convStream (liftM (map rstrip) getChunk)
De todos modos, con el enumeratee despojar disponible, es fácil compuesta con el enumLinesBS
enumeratee:
enumStripLines :: Monad m => Enumeratee ByteString [ByteString] m a
enumStripLines = enumLinesBS ><> rstripE
El operador de composición ><>
sigue el mismo orden que el operador de flecha >>>
. enumLinesBS
divide el flujo en líneas, luego rstripE
las tiras.Ahora sólo tiene que añadir un consumidor (que es un iteratee normal), y ya está:
writer :: FilePath -> Iteratee [ByteString] IO()
writer fp = I.mapM_ (B.appendFile fp)
processFile iFile oFile =
enumFile defaultBufSize iFile (joinI $ enumStripLines $ writer oFile) >>= run
Los fileDriver
funciones son atajos para simplemente enumerar más de un archivo y ejecutar la desgracia, el orden de los argumentos que resulta iteratee (se cambia de enumFile):
procFile2 iFile oFile = fileDriver (joinI $ enumStripLines $ writer oFile) iFile
Adición: he aquí una situación en la que se necesita la potencia extra de convStream. Supongamos que quiere concatenar cada 2 líneas en una. No puede usar mapChunks
. Considere cuando el fragmento es un elemento singleton, [bytestring]
. mapChunks
no proporciona ninguna forma de acceder al siguiente fragmento, por lo que no hay nada más que concatenar con esto. Con convStream
sin embargo, es muy sencillo:
concatPairs = convStream $ do
line1 <- I.head
line2 <- I.head
return $ line1 `B.append` line2
esto se ve aún mejor en el estilo aplicativo,
convStream $ B.append <$> I.head <*> I.head
que se pueda imaginar convStream
consumir como continuamente una porción de la corriente con el iteratee proporcionado, a continuación, enviar el versión transformada para el consumidor interno. A veces, incluso esto no es lo suficientemente general, ya que se llama a la misma iteración en cada paso. En ese caso, puede usar unfoldConvStream
para pasar el estado entre iteraciones sucesivas.
convStream
y unfoldConvStream
también permiten acciones monádicas, ya que el iteratee de procesamiento de flujo es un transformador de mónada.
John, ¡gracias por esta respuesta extremadamente detallada! Esto es exactamente lo que necesitaba. –
Dos notas pequeñas: el tipo de rstripE necesita un calificador de clase de tipo (Monad m) =>, y mi función rstrip necesita pegar una nueva línea en el extremo para integrar con enumLinesBS. De lo contrario, funciona como un encanto! –
Gracias por señalar esto, he agregado el contexto de clase de tipo. –