haskell - simbolos - ¿Cuál es la forma preferida de combinar dos sumideros?
salir de haskell (2)
He usado zipSinks :: Monad m => Sink imr -> Sink imr'' -> Sink im (r, r'')
para esto, pero se considera obsoleto.
((El paquete es conduit-0.5.2.3 . Todo el module es solo para compatibilidad con versiones anteriores.))
[ editar ]
Por lo tanto, mi suposición simple y monádica ( ver más abajo ) parece estar equivocada , aunque los tipos sean correctos. Ahora, solo puedo adivinar que la respuesta es:
Las funciones de reemplazo aún están en desarrollo, al igual que todas las tuberías y conductos y conceptos y bibliotecas similares.
Espero a que la próxima API resuelva esta pregunta y siga usando zipSink
hasta entonces. (Tal vez fue simplemente fuera de lugar.)
[ / editar ]
No estoy tan familiarizado con este paquete, ¿pero no haría 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 una Monad después de todo. ( Functor , Applicative )
zipSinks :: Monad sink => sink r -> sink r'' -> sink (r, r'')
zipSinks s1 s2 = liftM2 (,) s1 s2
Editar
Después de considerar esto, no creo que sea posible con la versión actual de Data.Conduit. Las tuberías no son categorías, por lo que &&&
está fuera de cuestión. Y no se me ocurre ninguna forma de obtener resultados del flujo ascendente, enviarlos de forma incremental a ambos sumideros y cortocircuitarlos cuando finaliza 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 la coincidencia de patrones en ambos Sinks (como lo hace zipSinks
en el paquete), Pero eso es lo que estamos tratando de evitar aquí.
Dicho esto, me encantaría estar equivocado aquí.
No es bonito, pero puedes hacer esto de una manera bastante 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)
Ahora para zipSinks
. Básicamente, usted desea crear un receptor que extraiga la entrada del flujo ascendente y lo envíe a cada receptor secundario por separado. En este caso, he usado CL.sourceList
para hacer esto. Si maybeToList
devuelve Nothing
, maybeToList
devuelve una lista vacía, por lo que los sumideros secundarios también se ejecutan sin entrada. Finalmente, la salida de cada fregadero infantil 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 de zipSinks
usar zipSinks
. Parece que funciona 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 con los antiguos 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)