2012-04-02 10 views
33

Me gustaría saber de alguien con una comprensión más profunda que yo las diferencias fundamentales entre Enumerators, Conduits y Pipes, así como los principales beneficios y desventajas. Algunos discussion's alreadyongoing pero sería bueno tener una visión general de alto nivel.¿Cuáles son los pros y los contras de los enumeradores frente a los conductos frente a los tubos?

+4

Los conductos y las tuberías aún están siendo sometidos a una gran revisión, por lo que es difícil compararlos y contrastarlos hasta que se estabilicen. En la situación ideal, los conductos y tuberías se fusionarán en la forma correcta de hacer enumeradores. –

Respuesta

28

Los enumeradores/Iteratos como abstracción fueron inventados por Oleg Kiselyov. Proporcionan una forma limpia de hacer IO con requisitos de recursos predecibles (bajos). El paquete de Enumerators actual es bastante similar al trabajo original de Oleg.

Los conductos se crearon para el marco web Yesod. Tengo entendido que fueron diseñados para ser increíblemente rápidos. Las primeras versiones de la biblioteca eran muy explícitas.

Las tuberías se centran en la elegancia. Tienen un solo tipo en lugar de varios, forman instancias de mónada (transformador) y categoría, y tienen un diseño muy "funcional".

Si te gusta explicaciones categóricas: el tipo Pipe es sólo la mónada gratuita a través de la siguiente funtor sencilla impíos

data PipeF a b m r = M (m r) | Await (a -> r) | Yield b r 
instance Monad m => Functor (PipeF a b m) where 
    fmap f (M mr) = M $ liftM mr 
    fmap f (Await g) = Await $ f . g 
    fmap f (Yield b p) = Yield b (f p) 
--Giving: 
newtype Pipe a b m r = Pipe {unPipe :: Free (PipeF a b m) r} 
    deriving (Functor, Applicative, Monad) 

--and 
instance MonadTrans (Pipe a b) where 
    lift = Pipe . inj . M 

En la definición tubería actual éstos se cuecen en, pero la simplicidad de esta definición es increíble. Las tuberías forman una categoría en la operación (<+<) :: Monad m => Pipe c d m r -> Pipe a b m r -> Pipe a d m r que toma la primera tubería yields y la envía a la segunda tubería en espera.

Parece que Conduits se mueve a ser más Pipe como (usando CPS en lugar de estado, y el cambio a un solo tipo), mientras que los tubos están ganando apoyo para un mejor manejo de errores, y tal vez el regreso de los tipos separados para los generadores y consumidores .

Esta área se está moviendo rápidamente. He estado pirateando una variante experimental de la biblioteca Pipe con estas características, y sé que otras personas también (ver el paquete Guarded Pipes en Hackage), pero sospecho que Gabriel (el autor de Pipes) las resolverá antes que yo. hacer.

Mis recomendaciones: si está utilizando Yesod, utilice Conductos. Si quieres una biblioteca madura usa Enumerator. Si te preocupas por la elegancia, utiliza Pipe.

7

Después de escribir aplicaciones con las tres bibliotecas, creo que la mayor diferencia que he visto es cómo se maneja la finalización de recursos. Por ejemplo, Pipes divide la finalización del recurso en tipos separados de marcos y pilas.

También parece haber aún cierto debate sobre cómo no solo finalizar el recurso de entrada, sino también potencialmente el recurso de salida. Por ejemplo, si está leyendo desde un DB y está escribiendo en un archivo, la conexión para el DB debe cerrarse, así como el archivo de salida que necesita ser enjuagado y cerrado. Las cosas se ponen feas cuando se decide cómo manejar excepciones y casos de fallas a lo largo de la tubería.

Otra diferencia más sutil parece ser cómo se maneja y se calcula el valor de retorno de la tubería del enumerador.

Muchas de estas diferencias y posibles incoherencias han quedado al descubierto por el uso de las implementaciones Monad y Category para Pipes y ahora están abriéndose paso en Conduits.

Cuestiones relacionadas