parsing - 将普通的 attoparsec 解析器代码转换为基于管道/管道的代码

标签 parsing haskell conduit attoparsec haskell-pipes

我使用 attoparsec 编写了以下解析代码:

data Test = Test {
  a :: Int,
  b :: Int
  } deriving (Show)

testParser :: Parser Test
testParser = do
  a <- decimal
  tab
  b <- decimal
  return $ Test a b

tParser :: Parser [Test]
tParser =  many' $ testParser <* endOfLine

这适用于小文件,我是这样执行的:
main :: IO ()
main = do
  text <- TL.readFile "./testFile"
  let (Right a) = parseOnly (manyTill anyChar endOfLine *> tParser) text
  print a  

但是当文件大小大于 70MB 时,它会消耗大量内存。作为解决方案,我想我会使用 attoparsec-conduit .经过他们的API ,我不知道如何让它们一起工作。我的解析器的类型是 Parser Test但它是 sinkParser实际上接受 Parser a b 类型的解析器.我对如何在常量内存中执行这个解析器感兴趣? (基于管道的解决方案也是可以接受的,但我不习惯管道 API。)

最佳答案

Parser的第一个类型参数只是输入的数据类型( TextByteString )。您可以提供您的 testParser函数作为 sinkParser 的参数它会正常工作。这是一个简短的例子:

{-# LANGUAGE OverloadedStrings #-}
import           Conduit                 (liftIO, mapM_C, runResourceT,
                                          sourceFile, ($$), (=$))
import           Data.Attoparsec.Text    (Parser, decimal, endOfLine, space)
import           Data.Conduit.Attoparsec (conduitParser)

data Test = Test {
  a :: Int,
  b :: Int
  } deriving (Show)

testParser :: Parser Test
testParser = do
  a <- decimal
  space
  b <- decimal
  endOfLine
  return $ Test a b

main :: IO ()
main = runResourceT
     $ sourceFile "foo.txt"
    $$ conduitParser testParser
    =$ mapM_C (liftIO . print)

关于parsing - 将普通的 attoparsec 解析器代码转换为基于管道/管道的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24058882/

相关文章:

haskell - 管道:提取后续数字

java - 将 XML 解析为 Java

c++ - 程序统计工具

haskell - 在 Haskell 中修改 Map of Maps

Haskell:检查 IO 的长度 [Double]

haskell - 管道:只读来源可能吗?

perl - 如何在 Perl 中有效地解析 CSV 文件?

javascript - JSON解析文件路径

generics - 自由箭头的有用操作

windows - Windows 8 上的 "InternalIOException getAddrInfo: does not exist (error 10093)"