Трубы: открыть файл в соответствии с содержанием другого
У меня есть этот код:
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
Но это выглядит довольно странно, и я хотел бы иметь возможность открыть второй файл из трубы, из того, что я прочитал в первой строке первого файла. Любая идея?
1 ответ
Есть, я думаю, несколько способов сделать это без смешивания Data.Text.IO
в с Pipes
вещи. Это в основном 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
кроме того, что он течет правильно.