每个管道在发送到下游之前进行评估?

时间:2014-08-05 15:24:40

标签: haskell haskell-pipes

通过pipes tutorial导致玩弄了一些例子:

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

但以上产生:

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

与我的预期相反,f1和f2会产生相同的结果(即f2的结果)。问题是:为什么不呢?

1 个答案:

答案 0 :(得分:4)

For具有以下类型的签名:

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'

for的第二个参数是:

(lift . putStrLn . show)

哪个类型为b -> Proxy ...,但由于yield不存在,因此不会产生下游任何内容。这意味着P.takeP.stdoutLn永远不会运行。由于P.take没有收到任何值,因此它不会关闭管道。

如果您想使用for打印价值并向下游收益,您可以:

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

编辑:

以下是基于使用f1的{​​{1}}的其他代码示例:

for