Haskell 使用pipes 4.0折叠流的子集

Haskell 使用pipes 4.0折叠流的子集,haskell,conduit,haskell-pipes,Haskell,Conduit,Haskell Pipes,我试图理解Pipes4.0,并希望转换一些导管代码。假设我有一个Ints流,我想跳过前五个,然后得到下面五个的总和。使用普通列表,这将是: sum . take 5 . drop 5 drop 5 isolate 5 =$ fold (+) 0 在管道中,这将是: sum . take 5 . drop 5 drop 5 isolate 5 =$ fold (+) 0 或者作为一个完整的程序: import Data.Conduit import Data.Conduit.List (d

我试图理解Pipes4.0,并希望转换一些导管代码。假设我有一个
Int
s流,我想跳过前五个,然后得到下面五个的总和。使用普通列表,这将是:

sum . take 5 . drop 5
drop 5
isolate 5 =$ fold (+) 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
导入数据。管道
导入Data.conductor.List(放置、隔离、折叠)
导入前奏隐藏(拖放)
main::IO()
main=do

res我以前没有使用过管道,但读完教程后,我发现它非常简单:

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
更新:

由于示例中没有“有效”处理,我们甚至可以使用
Identity
monad作为管道的基本monad:

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
更新1

下面是我提出的解决方案(对于要点链接评论),但我觉得它可以变得更加优雅

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"
fun::管道Int(Int,Int)标识()
乐趣=做
复制项目5等待
一个有趣的地方
f(仅(a,b))=打印(a,b)
f Nothing=打印“数据不足”

为了回答您的评论,这在一般情况下仍然有效。我也在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
导入管道
导入管道。解析
进口合格管道。前奏部分为P
main::IO()
main=do
res->P.take 5)丢弃
P.sum(输入>->P.take 5)
打印资源

这将推广到您所想到的更复杂的情况。

但管道具有相同的取、降和降fold@SassaNF管道中的
折叠
类型与导管中的类型明显不同,这就是混淆的原因。谢谢,这就是我要找的。我尝试了一些类似的方法,但没有成功,尽管我似乎找不到它是什么。事实上,我认为我最终被这个稍微复杂一点的例子绊倒了,但这实际上是一个单独的问题。如果您对此有任何想法,请告诉我,否则我将把它作为自己的问题来打开。请注意,您也可以使用
sum
管道,但这仍然是一个非常好的答案。我知道该答案给出了相同的结果,但与要点大不相同。(1) 它将值读入内存,而不是进行流式折叠。(2) 对于
sum
的情况,这很好,但是如果使用者是更复杂的东西(例如,zlib压缩并保存到文件),我们不能只引入
Prelude
函数。(3) 如果没有足够的输入,它的行为会有所不同。