I'm trying to understand pipes 4.0, and want to convert some conduit code. Suppose I have a stream of Int
s, and I'd like to skip the first five, then get the sum of the following 5. Using plain lists, this would be:
sum . take 5 . drop 5
In conduit, this would be:
drop 5
isolate 5 =$ fold (+) 0
Or as a complete program:
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
However, I'm not quite certain how to do this with pipes.
To answer your comment, this still works in the general case. I also posted the same answer on reddit where you also asked a similar question there, but I'm duplicating the answer here:
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
This will generalize to the more complicated cases that you had in mind.
I haven't used Pipes before, but after going through the tutorial I found it really simple:
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:
As there is no "effectful" processing in the example we can even use Identity
monad as the base monad for pipe:
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
UPDATE 1:
Below is the solution I came up with (for the gist link comment), but I feel like it can be made more elegant
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"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With