管道:根据另一个文件的内容打开文件

时间:2016-08-24 14:07:48

标签: haskell haskell-pipes

我有这段代码:

import Pipes
import Pipes.Safe
import qualified Pipes.Prelude as P
import qualified Pipes.Safe.Prelude as P
import System.IO

import Data.Text as T
import Data.Text.IO as TIO
import qualified Pipes.Prelude.Text as T

someFunc :: IO ()
someFunc = runSafeT $
  P.withFile file1 ReadMode $ \file1Handle -> do
    file2 <- liftIO $ TIO.hGetLine file1Handle
    runEffect $
      for (P.zip (T.fromHandleLn file1Handle)
                 (T.readFileLn $ T.unpack file2))
          (\(l1,l2) -> do yield l2
                          yield l1)
      >-> T.stdoutLn

但它似乎相当hacky,我希望能够从管道中打开第二个文件,从我在第一个文件的第一行读到的。 有什么想法吗?

1 个答案:

答案 0 :(得分:2)

我认为有很多方法可以将Data.Text.IOPipes混合在一起。正如你所说,它基本上是zip。查找第一个文件第一行的自然方法就是使用next,在这种情况下,它会为您提供与其余行配对的第一行:

someFunc_ = runSafeT $ runEffect $ do 
  e <- next (T.readFileLn file1)
  case e of
    Left r              -> return r
    Right (file2, rest) -> do 
      let other = T.readFileLn (T.unpack file2)
          amalgam = for (P.zip rest other) $ \(l1,l2) -> do
            yield l2 
            yield l1
      runEffect $ amalgam >-> T.stdoutLn

我认为一种试图在管道内做更多事情的方法最终会变得比它值得更复杂。特别是,您必须处理file1变为空的情况。 next基本上是用于在管道Producer上模式匹配的,因此它是一个基本的管道操作。

所以,部分原因,它与像这样的普通文本程序基本相同

 someFunc = do
    ls <- fmap T.lines TIO.readFile file1 
    case ls of
      []         -> return ()
      file2:rest -> do 
        ls' <- fmap T.lines (TIO.readFile file1) 
        forM_ (zip ls ls') $ \(t1,t2) -> do
             TIO.putStrLn t1
             TIO.putStrLn t2

除了它正确地流。