2012-05-31 6 views
9

У меня простая задача - прочитать кучу строк из файла и сделать что-то с каждым из них. За исключением первого - некоторые заголовки игнорируются.Как использовать функцию каплеотвода в трубопроводе?

Так что я думал, что попробую кабелепроводы.

printFile src = runResourceT $ CB.sourceFile src =$= 
    CT.decode CT.utf8 =$= CT.lines =$= CL.mapM_ putStrLn 

Прохладный.

Так что теперь я просто хочу, чтобы бросить первую строку выключить ... и там, кажется, есть функция для этого -

printFile src = runResourceT $ CB.sourceFile src =$= 
    CT.decode CT.utf8 =$= CT.lines =$= drop 1 =$= CL.mapM_ putStrLn 

Хм, - но теперь я замечаю падение имеет тип подписи Sink a m(). Кто-то предложил мне, что я могу использовать экземпляр Monad для труб и использования капли для effectfully уронить некоторые элементы - так что я попытался это:

drop' :: Int -> Pipe a a m() 
drop' n = do 
    CL.drop n 
    x <- await 
    case x of 
    Just v -> yield v 
    Nothing -> return() 

Что не тип проверки, поскольку монада экземпляр для труб применяется только к трубам одного и того же типа - у Sinks есть Void в качестве вывода, поэтому я не могу использовать его так.

Я быстро посмотрел на трубы и трубы, и я заметил, что в трубном сердечнике есть функция, как я ожидал, поскольку, поскольку трубы являются минимальной библиотекой, но документация показывает, как она будет реализована.

Так что я запутался - может быть, есть ключевое понятие я пропускаю .. Я видел функцию

sequence :: Sink input m output -> Conduit input m output 

Но это, кажется, не быть правильной идеей, так как выходное значение ()

CL.sequence (CL.drop 1) :: Conduit a m()  

Я, вероятно, просто вернуться назад и использовать ленивый-IO, как я на самом деле не нужен потоковый - но я бы интересно посмотреть, как правильно это сделать.

ответ

6

Во-первых, простой ответ:

... =$= CT.lines =$= (CL.drop 1 >> CL.mapM_ putStrLn) 

Чем длиннее объяснение: на самом деле есть два различных способа можно реализовать drop. В любом случае, он сначала упадет на n элементов. Есть два варианта о том, что он делает следующий:

  • говорит, что это сделано
  • Start выводит все остальные элементы из входного потока

Первое поведение то, что Sink будет выполнять (и что наш drop действительно), а последнее - поведение Conduit. Вы можете фактически произвести последние из первых через монадическую композицию:

dropConduit n = CL.drop n >> CL.map id 

Затем вы можете использовать dropConduit как вы описали в самом начале. Это хороший способ продемонстрировать разницу между монадической композицией и сплавлением; первый позволяет двум функциям работать на одном и том же входном потоке, а последний позволяет одной функции подавать поток в другой.

Я не тестировал, но я уверен, что монадическая композиция будет немного более эффективной.

+0

Хм - простой ответ работает хорошо, спасибо. dropConduit - это «Monad m => Int -> Pipe Void Void m()», который, по моему мнению, довольно сложно использовать для чего-либо, что я думаю? – Oliver

+0

Извините, я работаю над другой версией кодовой базы, где это не применимо. В канале 0.4 вам понадобится 'sinkToPipe (CL.drop n) >> CL.map id'. Проблема в том, что типы в Data.Conduit.List являются чрезмерно ограничительными. трубопровод 0,5 будет расслаблять их. –

+0

Ahh - приветствия. В этом есть смысл. – Oliver

Смежные вопросы