sreekar
sreekar

Reputation: 57

pipes for each evaluates before sending downstream?

going through the pipes tutorial led to toying with some examples:

import Pipes
import qualified Pipes.Prelude as P

f1 :: Show a => Int -> [a] -> IO ()
f1 n xs = runEffect $ (for (each xs) (lift . putStrLn . show))
            >-> P.take n
            >-> P.stdoutLn

f2 :: Show a => Int -> [a] -> IO ()
f2 n xs = runEffect $ each xs
            >-> P.map show
            >-> P.take n
            >-> P.stdoutLn

but the above produces:

>>> f1 3 [1..10]
1
2
3
4
5
6
7
8
9
10
>>> f2 3 [1..10]
1
2
3
>>>

contrary to my expectation that f1 and f2 would produce the same result (namely the result of f2). the question is: why don't they?

Upvotes: 1

Views: 63

Answers (1)

Davorak
Davorak

Reputation: 7444

For has the type signature of:

for
  :: Monad m =>
     Proxy x' x b' b m a'
     -> (b -> Proxy x' x c' c m b') -> Proxy x' x c' c m a'

You second parameter for your for is:

(lift . putStrLn . show)

Which is has a type of b -> Proxy ..., but does not yield anything downstream since yield is absent. This means that P.take and P.stdoutLn never run. Since P.take does not receive any values it does not ever shutdown the pipeline.

If you wanted to print the value with for and yield downstream you could:

f1 :: Show a => Int -> [a] -> IO ()
f1 n xs = runEffect $ (for (each xs) 
                           (\x -> (lift . putStrLn . show) x >> yield x))
            >-> P.show
            >-> P.take n
            >-> P.stdoutLn


> f1 3 [1..10]
1
1
2
2
3
3

edit:

Here are some additional code samples based on f1 using for:

f3 :: Show a => Int -> [a] -> IO ()
f3 n xs = runEffect $ for (each xs >-> P.take n) (lift . putStrLn . show)  

f4 :: Show a => Int -> [a] -> IO ()
f4 n xs = runEffect $ each [1..10] >-> for (P.take n) (lift . putStrLn . show)

> f3 3 [1..10]
1
2
3
> f4 3 [1..10]
1
2
3

Upvotes: 4

Related Questions