如何在管道中使用管道掉落功能?

Oli*_*ver 9 haskell pipe conduit

我有一个简单的任务 - 从文件中读取一堆行并对其中的每一行执行一些操作.除了第一个 - 这是一些可以忽略的标题.

所以我想我会试试管道.

printFile src = runResourceT $ CB.sourceFile src =$= 
    CT.decode CT.utf8 =$= CT.lines =$= CL.mapM_ putStrLn
Run Code Online (Sandbox Code Playgroud)

凉.

所以现在我只想放弃第一行...而且似乎有一个功能 -

printFile src = runResourceT $ CB.sourceFile src =$= 
    CT.decode CT.utf8 =$= CT.lines =$= drop 1 =$= CL.mapM_ putStrLn
Run Code Online (Sandbox Code Playgroud)

嗯 - 但现在我注意到drop有类型签名Sink a m ().有人向我建议我可以使用Monad实例来管道并使用drop来有效地删除一些元素 - 所以我尝试了这个:

drop' :: Int -> Pipe a a m ()
drop' n = do
  CL.drop n
  x <- await
  case x of 
    Just v -> yield v
    Nothing -> return ()
Run Code Online (Sandbox Code Playgroud)

哪个不进行类型检查,因为管道的monad实例仅适用于相同类型的管道 - Sinks将Void作为其输出,因此我不能像这样使用它.

我快速浏览了一下管道和管道核心,我注意到管道核心具有我预期的功能,管道是一个最小的库,但文档显示了它将如何实现.

所以我很困惑 - 也许有一个我错过的关键概念..我看到了这个功能

sequence ::  Sink input m output -> Conduit input m output
Run Code Online (Sandbox Code Playgroud)

但这似乎不是正确的想法,因为输出值是()

CL.sequence (CL.drop 1) :: Conduit a m ()    
Run Code Online (Sandbox Code Playgroud)

我可能只是回去使用lazy-io,因为我不需要任何流媒体 - 但我有兴趣看到正确的方法来做到这一点.

Mic*_*man 6

首先,简单的答案:

... =$= CT.lines =$= (CL.drop 1 >> CL.mapM_ putStrLn)
Run Code Online (Sandbox Code Playgroud)

更长的解释:实际上有两种不同的方式可以实现drop.无论哪种方式,它将首先n从输入中删除元素.关于下一步做什么有两种选择:

  • 说它已经完成了
  • 开始输出输入流中的所有剩余项目

前者的行为是什么Sink(以及我们drop实际做了什么),而后者是行为Conduit.实际上,你可以通过monadic组合从前者生成后者:

dropConduit n = CL.drop n >> CL.map id
Run Code Online (Sandbox Code Playgroud)

然后你可以dropConduit按照你在开头描述的那样使用.这是展示monadic成分和融合之间差异的好方法; 前者允许两个函数在同一输入流上操作,而后者允许一个函数将流馈送到另一个.

我没有基准测试,但我相当确定monadic组合会更有效率.