2012-05-31 8 views
9

Tengo una tarea simple: leer un montón de líneas de un archivo y hacer algo con cada una de ellas. Excepto el primero, que son algunos títulos que deben ignorarse.¿Cómo usar la función de caída de conducto en una tubería?

Así que pensé en probar los conductos.

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

Cool.

Así que ahora sólo quiere pasar la primera línea de ... y parece que hay una función para la que -

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

Hmm - pero ahora puedo tener gota tiene el tipo de firma Sink a m(). Alguien me sugirió que puedo utilizar la instancia de Monad para tubos y uso gota a gota effectfully algunos elementos - lo que he intentado esto:

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

cual no quiere tipo de comprobación porque la instancia mónada para tuberías sólo se aplica a las tuberías del mismo tipo - Los sumideros tienen Void como salida, así que no puedo usarlo así.

Eché un vistazo rápido a pipes and pipes-core y noté que pipes-core tiene la función que esperaba, mientras que las tuberías son una biblioteca mínima pero la documentación muestra cómo se implementaría.

Así que estoy confundido - tal vez hay un concepto clave que me falta .. vi la función

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

Pero eso no parece ser la idea correcta, como el valor de salida es ()

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

probablemente voy a ir hacia atrás y uso perezoso-io como yo realmente no necesita ninguna streaming - pero estaría interesado en ver la forma correcta de hacerlo.

Respuesta

6

En primer lugar, la respuesta simple:

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

La explicación más tiempo: en realidad hay dos formas diferentes que se pueden implementar drop. De cualquier forma, primero soltará los elementos n de la entrada. Hay dos opciones acerca de lo que hace al lado:

  • dice que ha hecho
  • comenzarán a generar todos los elementos restantes de la corriente de entrada

El comportamiento anterior es lo que un Sink realizaría (y lo que realmente hace nuestro drop) mientras que el último es el comportamiento de un Conduit. De hecho, puede generar la última de la anterior composición a través monádico:

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

continuación, puede utilizar dropConduit como usted la describe al principio. Esta es una buena forma de demostrar la diferencia entre la composición monádica y la fusión; el primero permite que dos funciones operen en el mismo flujo de entrada, mientras que el segundo permite que una función alimente un flujo al otro.

No he realizado comparaciones, pero estoy bastante seguro de que la composición monádica será un poco más eficiente.

+0

Hmm - la respuesta simple funciona bien, gracias. dropConduit es 'Monad m => Int -> Pipe Void Void m()' que creo que hace que sea bastante difícil de usar para todo lo que pienso? – Oliver

+0

Lo siento, estoy trabajando en una versión diferente de la base de código donde eso no se aplicaría. En el conducto 0.4, necesitarías 'sinkToPipe (CL.drop n) >> CL.map id'. El problema es que los tipos en Data.Conduit.List son demasiado restrictivos. el conducto 0.5 los relajará. –

+0

Ahh - aplausos. Eso tiene sentido. – Oliver

Cuestiones relacionadas