在管道中跳过第一行 - attoparsec

Sib*_*ibi 4 haskell attoparsec haskell-pipes

我的类型:

data Test = Test {
 a :: Int,
 b :: Int
} deriving (Show)
Run Code Online (Sandbox Code Playgroud)

我的解析器:

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

tab = char '\t'
Run Code Online (Sandbox Code Playgroud)

现在为了跳过第一行,我做了这样的事情:

import qualified System.IO as IO    

parser :: Parser Test
parser = manyTill anyChar endOfLine *> testParser

main = IO.withFile testFile IO.ReadMode $ \testHandle -> runEffect $
         for (parsed (parser <* endOfLine) (fromHandle testHandle)) (lift . print)
Run Code Online (Sandbox Code Playgroud)

但是上面的parser函数会使每个备用链接跳过(很明显).如何以与Pipes生态系统一起工作的方式跳过第一行(Producer应该产生单个Test值.)这是一个我不想要的明显解决方案(下面的代码只有在我修改testParser读取换行符时才有效)因为它返回整个[Test]而不是单个值:

tests :: Parser [Test]
tests = manyTill anyChar endOfLine *>
        many1 testParser
Run Code Online (Sandbox Code Playgroud)

有什么想法来解决这个问题吗?

Zet*_*eta 5

如果第一行不包含任何有效Test,您可以使用Either () Test它来处理它:

parserEither :: Parser (Either () Test)
parserEither = Right <$> testParser <* endOfLine 
           <|> Left <$> (manyTill anyChar endOfLine *> pure ())
Run Code Online (Sandbox Code Playgroud)

在此之后,您可以使用提供的函数Pipes.Prelude来删除第一个结果(以及所有不可解析的行):

producer p = parsed parserEither p 
         >-> P.drop 1 
         >-> P.filter (either (const False) (const True))
         >-> P.map    (\(Right x) -> x)

main = IO.withFile testFile IO.ReadMode $ \testHandle -> runEffect $
         for (producer (fromHandle testHandle)) (lift . print)
Run Code Online (Sandbox Code Playgroud)


Gab*_*lez 5

您可以在常量空间中有效地删除第一行,如下所示:

import Lens.Family (over)
import Pipes.Group (drops)
import Pipes.ByteString (lines)
import Prelude hiding (lines)

dropLine :: Monad m => Producer ByteString m r -> Producer ByteString m r
dropLine = over lines (drops 1)
Run Code Online (Sandbox Code Playgroud)

您可以应用dropLine到你的Producer,你解析之前Producer,就像这样:

main = IO.withFile testFile IO.ReadMode $ \testHandle -> runEffect $
    let p = dropLine (fromHandle testHandle)
    for (parsed (parser <* endOfLine) p) (lift . print)
Run Code Online (Sandbox Code Playgroud)