2012-02-10 8 views
3

У меня есть проблемы с кодом с помощью network-conduit:как добавить новый источник внутри Haskell трубопровода

import Data.Conduit.List as CL 
import Data.Conduit.Text as CT 
import qualified Data.ByteString.Char8 as S8 
import qualified Data.Text as TT 

mySource :: ResourceT m => Integer -> Source m Int 
mySource i = {- function -} undefined 

myApp :: Application 
myApp src snk = 
    src $= CT.decode CT.ascii 
     $= CL.map decimal 
     $= CL.map {-problem here-} 
     $$ src 

в проблеме месте я хочу написать что-то вроде

\t -> case t of 
    Left err = S8.pack $ "Error:" ++ e 
    Right (i,xs) = (>>>=) mySource 
       {- or better: 
        do 
        (>>>=) mySource 
        (<<<=) T.pack xs 
        -} 

где (>>>=) функция толкает mySource выход на новый уровень и (<<<=) отправляет функцию обратно на предыдущий уровень

+0

Поддерживает ли 'conduit' отправку данных вверх по течению? Я знаю, что «трубы». Возможно, вам понадобится использовать «трубы» для вашего варианта использования. – Cactus

+0

«Conduit» может возвращать данные обратно в свой собственный вход с 'leftover', но здесь« Conduit »хочет вставить вход обратно в его входной сигнал« Conduit », что невозможно. В этой ситуации следует использовать анализатор 'Conduit'. – pat

ответ

1

Сеть прерывает поток байтов в произвольные ByteString куски. С приведенным выше кодом эти фрагменты ByteString будут отображены на куски Text, и каждый фрагмент Text будет проанализирован как decimal. Однако строка десятичных цифр, представляющая один decimal, может быть разделена на два (или более) Text фрагментов. Кроме того, как вы понимаете, использование decimal возвращает вам оставшуюся часть фрагмента Text, которая не анализируется как часть decimal, которую вы пытаетесь вернуть обратно во входной поток.

Обе эти проблемы можно решить, используя Data.Conduit.Attoparsec. conduitParserEither с Data.Attoparsec.Text.decimal. Обратите внимание, что недостаточно просто разобрать decimal; вам также потребуется обработать какой-то разделитель между decimal с.

Он также не представляется возможным сращивание Source от CL.map, так как CL.map «s тип подписи

map :: Monad m => (a -> b) -> Conduit a m b 

Функция вы передаете map получает возможность трансформировать каждый вход a в один выход b, а не поток b. Для этого вы можете использовать awaitForever, но вам нужно будет преобразовать Source в общий Producer с toProducer, чтобы типы соответствовали.

Однако в вашем коде, вы пытаетесь отправить ошибки синтаксического анализа ниже по течению, как ByteString-х, но выход mySource как Int 'с, что ошибка типа. В обоих случаях вы должны указать поток ByteString; успешный разбор случай может вернуть Conduit сделанного сплавление другого Conduit «ы до тех пор, как она заканчивается с выходом ByteString:

... 
$= (let f (Left err) = yield $ S8.pack $ "Error: " ++ show err 
     f (Right (_, i)) = toProducer (mySource i) $= someOtherConduit 
    in awaitForever f) 

где someOtherConduit потопит Int» S от mySource, и источников ByteString «s.

someOtherConduit :: Monad m => Conduit Int m ByteString 

Наконец, я полагаю, вы имели в виду, чтобы соединить snk в конце трубы вместо src.

+0

Код был написан для кабелепровода-0.4 или что-то в этом роде, где не было «Продюсеры», «Потребительские» и «Трубы» вообще, остатков тоже не было. У меня нет этой проблемы вокруг меня на 5 или более и не уверен, смогу ли я вспомнить, почему я так хотел решить эту проблему, и если ответ покрывает проблему, которую я действительно имел. Это говорит о правильных вещах, хотя в наши дни это может быть полезно людям, использующим кабельные каналы, поэтому я отмечаю их как принимаемые. – qnikst