¿Cuáles son las ventajas y desventajas de enumeradores, conductos y tuberías?

Resuelto Luke Hoersten asked hace 12 años • 2 respuestas

Me gustaría saber de alguien con un conocimiento más profundo que yo cuáles son las diferencias fundamentales entre enumeradores , conductos y tuberías , así como los principales beneficios y desventajas. Ya hay algunas discusiones en curso , pero sería bueno tener una descripción general de alto nivel.

Luke Hoersten avatar Apr 03 '12 04:04 Luke Hoersten
Aceptado

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

Se crearon conductos para el marco web de Yesod. Tengo entendido que fueron diseñados para ser increíblemente rápidos. Las primeras versiones de la biblioteca tenían mucho estado.

Las pipas 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 le gustan las explicaciones categóricas: el Pipetipo es solo la mónada libre sobre el siguiente funtor simple e impío

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 de tubería real, estos están integrados, pero la simplicidad de esta definición es sorprendente. Las tuberías forman una categoría bajo la operación (<+<) :: Monad m => Pipe c d m r -> Pipe a b m r -> Pipe a d m rque toma el primer tubo yieldsy lo alimenta al segundo tubo en espera.

Parece que se Conduitsestá volviendo más Pipeparecido (usando CPS en lugar de estado y cambiando a un solo tipo), mientras que Pipes está ganando soporte para un mejor manejo de errores y tal vez el regreso de tipos separados para 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 lo están haciendo (consulte el paquete Guarded Pipes en Hackage), pero sospecho que Gabriel (el autor de Pipes) las descubrirá antes de que yo hacer.

Mis recomendaciones: si estás usando Yesod, usa Conduits. Si desea una biblioteca madura, utilice Enumerator. Si lo que más te importa es la elegancia, utiliza Pipe.

Philip JF avatar Apr 03 '2012 01:04 Philip JF

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 los recursos. Por ejemplo, Pipes divide la finalización de recursos en tipos separados de Marcos y Pilas.

También parece haber todavía cierto debate sobre cómo finalizar no sólo el recurso de entrada, sino también potencialmente el recurso de salida. Por ejemplo, si está leyendo desde una base de datos y escribiendo en un archivo, la conexión de la base de datos debe cerrarse, así como el archivo de salida debe vaciarse y cerrarse. Las cosas se ponen complicadas a la hora de decidir cómo manejar las excepciones y los casos de error a lo largo del proceso.

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

Muchas de estas diferencias y posibles inconsistencias han quedado expuestas mediante el uso de las implementaciones Monad y Category para Pipes y ahora están llegando a Conduits.

Luke Hoersten avatar Jul 16 '2012 15:07 Luke Hoersten