He usado zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')
para esto, pero se considera obsoleto.¿Cuál es la forma preferida de combinar dos sumideros?
Respuesta
((El paquete es conduit-0.5.2.3. El conjunto module es sólo para la compatibilidad hacia atrás.))
[edición]
Por lo tanto, mi conjetura monádica sencilla (ver más abajo) parece ser incorrecto, aunque los tipos son correctos. Ahora, solo puedo adivinar que la respuesta es:
Las características de reemplazo están todavía en desarrollo, más o menos como todas las Pipe/Conduit y conceptos y bibliotecas similares.
Esperaría a la próxima API para resolver esta pregunta y aún usaría zipSink
hasta entonces. (quizás fue simplemente fuera de lugar.)
[/editar]
No soy tan familiarizados con este paquete, pero ¿no hacer lo mismo que esto?
zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')
zipSinks s1 s2 = (,) <$> s1 <*> s2
Es un Monad después de todo. (Functor, Applicative)
zipSinks :: Monad sink => sink r -> sink r' -> sink (r, r')
zipSinks s1 s2 = liftM2 (,) s1 s2
Los tipos son correctos, pero no son semánticos. Su versión de 'zipSinks' ejecutará sumideros consecutivamente y el primer receptor consumirá completamente la fuente. – tymmym
Editar
Después de considerar esto, no creo que es posible con la versión actual de Data.Conduit. Las tuberías no son categorías, por lo que &&&
está fuera de la cuestión. Y no hay forma de que se me ocurra extraer los resultados de la corriente ascendente, alimentarlos gradualmente a ambos sumideros y cortocircuitar cuando termina el primer sumidero. (Aunque no creo que Data.Conduit.Util.zipSinks
cortocircuite de esta manera, parece que sería muy deseable.) Excepto por supuesto, para coincidir con el patrón en ambos sumideros (como zipSinks
en el paquete), pero eso es lo que estamos tratando de evitar aquí.
Dicho esto, me gustaría amor que se demuestre que está mal aquí.
No es bonito, pero puede hacerlo de una forma obvia.
primeras importaciones:
module Main where
import Control.Monad.Trans
import Data.Conduit
import qualified Data.Conduit.Binary as CB
import qualified Data.Conduit.List as CL
import qualified Data.Conduit.Text as CT
import qualified Data.Conduit.Util as CU
import Data.Maybe
import Data.Text (unpack)
ya por zipSinks
. Básicamente, desea crear un receptor que extraiga la entrada desde la parte superior y la envíe a cada receptor secundario por separado. En este caso, he usado CL.sourceList
para hacer esto. Si await
devuelve Nothing
, maybeToList
devuelve una lista vacía, por lo que los contenedores secundarios también se ejecutan sin entrada. Finalmente, la salida de cada sumidero de niños se alimenta a la tupla.
zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')
zipSinks s1 s2 = do
l <- fmap maybeToList await
o1 <- lift $ CL.sourceList l $$ s1
o2 <- lift $ CL.sourceList l $$ s2
return (o1, o2)
Aquí hay algunos ejemplos del uso de zipSinks
. Parece funcionar bien tanto dentro de IO
como fuera de él, y en las pocas pruebas que hice, la salida coincide con la salida de zipped'
, creada usando el antiguo zipSinks
.
doubleHead :: Monad m => Sink Int m (Maybe Int)
doubleHead = await >>= return . fmap (2*)
-- old version
zipped' :: Monad m => Sink Int m (Maybe Int, Maybe Int)
zipped' = CU.zipSinks CL.head doubleHead
-- new version
zipped :: Monad m => Sink Int m (Maybe Int, Maybe Int)
zipped = zipSinks CL.head doubleHead
fromList = CL.sourceList [7, 8, 9] $$ zipped
-- (Just 7, Just 14)
fromFile :: String -> IO (Maybe Int, Maybe Int)
fromFile filename = runResourceT $
CB.sourceFile filename
$= CB.lines
$= CT.decode CT.utf8
$= CL.map (read . unpack)
$$ zipped
-- for a file with the lines:
--
-- 1
-- 2
-- 3
--
-- returns (Just 1, Just 2)
¡Agradable! (NB, podría escribir 'await >> = return. Fmap (2 *)' para 'doubleHead', y de manera similar,' l <- fmap maybeToList await' en lugar de usar 'input' en' zipSinks'. Además, es ' Data.Conduit.Internals' ¿una importación extraña?) – huon
Sí, me di cuenta de que probablemente podría haber usado funtores en algunos lugares. Todavía soy lo suficientemente n00b en Haskell, que por lo general es una edición de segundo pase para mí, desafortunadamente. Y sí, 'Data.Conduits.Internals' es extraño. Originalmente, estaba buscando usar 'sinkToPipe' a partir de él. Gracias por señalar esto. Actualizaré la respuesta. – Eric
Su versión de 'zipSinks' combina solo los primeros elementos. Por ejemplo 'runResourceT $ CL.sourceList [1,2,3] $$ zipSinks (CL.take 2) (CL.take 2)' devolverá '([1], [1])' pero debería '([1 , 2], [1,2]) '. – tymmym
- 1. ¿Forma preferida de combinar PHP y HTML?
- 2. Uso de la forma preferida de combinar Autofac y Dapper
- 3. Programación de DirectX en Windows, ¿cuál es la forma preferida?
- 4. ¿Cuál es la forma preferida de eventos de burbujas?
- 5. ¿Cuál es la forma preferida de implementar hashCode()?
- 6. ¿Cuál es la forma preferida de implementar una aplicación Symfony2?
- 7. ¿Cuál es la forma preferida de preasignar matrices NumPy?
- 8. ¿Cuál es la forma preferida de configurar una aplicación mono?
- 9. ¿Cuál es la forma preferida de pasar datos entre dos aplicaciones en el mismo sistema?
- 10. ¿Cuál es la forma más rápida de combinar dos archivos xml en uno
- 11. ¿Cuál es una forma eficiente de combinar dos almacenes persistentes de datos centrales de iOS?
- 12. ¿Cuál es la forma preferida de almacenar diferentes versiones de datos?
- 13. ¿Cuál es la forma preferida de realizar autenticación y autorización de usuario en Clojure?
- 14. ¿Cuál es la forma preferida de incluir fuentes QML en la creación de tu aplicación?
- 15. ¿Cuál es la forma preferida de usar métodos de ayuda en Ruby?
- 16. ¿Cuál es la forma preferida de encadenar las funciones de Underscore.js?
- 17. ¿Cuál es la forma preferida de salir de un programa de línea de comando?
- 18. ¿Cuál es la forma preferida de conectarse a una base de datos postgresql desde PHP?
- 19. ¿Cuál es la forma preferida de implementar un enlace o devolución de llamada en Python?
- 20. ¿Cuál es la forma preferida de hacer plantillas de sitios y temas con Wicket?
- 21. ¿Cuál es la forma preferida de implementar un método de fábrica en C++?
- 22. ¿Cuál es la forma preferida de hacer una renovación de CSS?
- 23. ¿Manera pitónica de combinar dos listas de forma alternativa?
- 24. ¿Cuál es la forma preferida de construir objetos en C#? ¿Parámetros o propiedades del constructor?
- 25. ¿Cuál es la forma preferida de pasar el puntero/referencia al objeto existente en un constructor?
- 26. ¿Cuál es la forma preferida de administrar el pedido en el patrón del generador?
- 27. ¿Cuál es la forma preferida de sangrar casos en un interruptor?
- 28. ¿Cuál es la forma preferida de mostrar imágenes grandes en OpenGL
- 29. ¿Cuál es la forma preferida de estructurar y construir proyectos OCaml?
- 30. ¿Cuál es la forma preferida de implementar configuraciones en una aplicación Ruby on Rails 3?
¿Qué comportamiento, * exactamente *, quieres que tengan los fregaderos "combinados"? Traté de ver la documentación anterior y la implementación de 'zipSinks', pero el comportamiento no es fácilmente discernible de un vistazo. –
@DanBurton: 'zipSinks' toma dos Sinks y devuelve un Sink que produce un par con los resultados de los correspondientes Sinks. Por ejemplo, 'sizeCrc32Sink = zipSinks sizeSink crc32Sink' contará el tamaño y la suma de comprobación. Yo qué tipo de comportamiento describe Oleg [aquí] (http://okmij.org/ftp/Streams.html#1enum2iter). – tymmym
Ok, ya veo; básicamente enlaza la espera y alimenta la salida ascendente a ambos sumideros simultáneamente, clasificando la secuencia de entrada en dos. Los documentos para Data.Conduit.Util afirman que "ahora hay formas más fáciles de manejar sus casos de uso", pero no veo una manera más fácil para este caso de uso, ya que requiere profundizar en el interior del conducto para implementarlo. –