2013-09-24 2 views
6

Я пытаюсь понять каналы 4.0 и хочу конвертировать некоторый код кабелепровода. Предположим, у меня есть поток Int с, и я хотел бы, чтобы пропустить первые пять, а затем получить сумму следующего 5. Используя простые списки, это было бы:Складывание подмножества потока с использованием труб 4.0

sum . take 5 . drop 5 

В трубопроводе, это будет :

drop 5 
isolate 5 =$ fold (+) 0 

Или как полной программе:

import Data.Conduit 
import Data.Conduit.List (drop, isolate, fold) 
import Prelude hiding (drop) 

main :: IO() 
main = do 
    res <- mapM_ yield [1..20] $$ do 
     drop 5 
     isolate 5 =$ fold (+) 0 
    print res 

Однако, я не совсем уверен, как сделать это с помощью труб.

+0

Но трубы имеют одинаковое положение, падение и сгиб –

+0

@SassaNF Тип 'fold' в трубах значительно отличается от типа в кабелепроводе, откуда и возникает путаница. –

ответ

5

Я не использовал Трубы и раньше, но после прохождения урока я нашел, что это очень просто:

import Pipes 
import qualified Pipes.Prelude as P 

nums :: Producer Int IO() 
nums = each [1..20] 

process :: Producer Int IO() 
process = nums >-> (P.drop 5) >-> (P.take 5) 

result :: IO Int 
result = P.fold (+) 0 id process 

main = result >>= print 

UPDATE:

Как нет «effectful» обработка в примере мы можем даже использовать Identity монады в качестве базовой монады для трубы:

import Pipes 
import qualified Pipes.Prelude as P 
import Control.Monad.Identity 

nums :: Producer Int Identity() 
nums = each [1..20] 

process :: Producer Int Identity() 
process = nums >-> (P.drop 5) >-> (P.take 5) 

result :: Identity Int 
result = P.fold (+) 0 id process 

main = print $ runIdentity result 

Обновит E 1:

Ниже решение, которое я придумал (для GIST ссылка комментарий), но я чувствую, что это можно сделать более элегантный

fun :: Pipe Int (Int, Int) Identity() 
fun = do 
    replicateM_ 5 await 
    a <- replicateM 5 await 
    replicateM_ 5 await 
    b <- replicateM 5 await 
    yield (sum a, sum b) 

main = f $ runIdentity $ P.head $ nums >-> fun where 
    f (Just (a,b)) = print (a,b) 
    f Nothing = print "Not enough data" 
+0

Спасибо, вот что я искал. Я попробовал нечто похожее на то, что не сработало, хотя я не могу найти, что это такое. –

+0

На самом деле, я думаю, что вещь, с которой я столкнулась, была очень сложной: https://gist.github.com/snoyberg/6683033, но это действительно отдельная проблема. Если у вас есть какие-либо идеи по этому поводу, дайте мне знать, иначе я просто открою его как свой собственный вопрос. –

+0

Обновлен мой ответ – Ankur

4

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

import Pipes 
import Pipes.Parse 
import qualified Pipes.Prelude as P 

main :: IO() 
main = do 
    res <- (`evalStateT` (each [1..20])) $ do 
     runEffect $ for (input >-> P.take 5) discard 
     P.sum (input >-> P.take 5) 
    print res 

Это обобщается на более сложные случаи, которые вы имели в виду.

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