Подтвердить что ты не робот

Каков предпочтительный способ объединения двух приемников?

Я использовал zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r') для этого, но считается устаревшим.

4b9b3361

Ответ 1

Edit

Рассмотрев это, я не думаю, что это возможно с текущей версией Data.Conduit. Трубы не являются категориями, поэтому &&& не может быть и речи. И нет никакого способа, чтобы я мог думать о том, чтобы вытащить результаты из восходящего потока, поэтапно кормить их обе стоки и короткое замыкание, когда заканчивается первая раковина. (Хотя я не думаю, что Data.Conduit.Util.zipSinks коротко замыкается таким образом, кажется, что это было бы очень желательно.) За исключением, конечно, соответствия шаблону на обоих Sinks (например, zipSinks в пакете), но это что мы пытаемся избежать здесь.

Тем не менее, я был бы рад оказаться здесь неправильно.


Это некрасиво, но вы можете сделать это очевидным образом.

Первый импорт:

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)

Теперь для zipSinks. В принципе, вы хотите создать раковину, которая тянет входной сигнал вверх и отправляет его каждому приемнику отдельно. В этом случае я использовал CL.sourceList для этого. Если await возвращает Nothing, maybeToList возвращает пустой список, поэтому дочерние потоки также запускаются без ввода. Наконец, вывод каждого дочернего приемника затем подается в кортеж.

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)

Вот несколько примеров использования zipSinks. Кажется, он отлично работает как внутри IO, так и за его пределами, а в нескольких проведенных тестах результат соответствует выводу zipped', созданного с использованием старого 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)

Ответ 2

((Пакет conduit-0.5.2.3. Весь модуль предназначен только для обратной совместимости.) )


[ изменить]

Итак, моя простая монадическая догадка (ниже) кажется неправильной, хотя типы верны. Теперь я могу только догадываться, что ответ таков:

Заменяющие функции все еще находятся в разработке, в значительной степени похожи на все Pipe/Conduit и аналогичные концепции и библиотеки.

Я бы подождал следующего API, чтобы решить этот вопрос и до сих пор использовать zipSink. (Возможно, это было просто неуместно.)

[/изменить]

Я не знакомый с этим пакетом, но не будет ли он таким же, как этот?

zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')
zipSinks s1 s2 = (,) <$> s1 <*> s2

Это Monad. (Functor, Applicative)

zipSinks :: Monad sink => sink r -> sink r' -> sink (r, r')
zipSinks s1 s2 = liftM2 (,) s1 s2