将多行解析为 Haskell 中的列表列表

Parsing multiple lines into a list of lists in Haskell

我正在尝试解析一个如下所示的文件:

a b c 
f e d

我想匹配行中的每个符号并将所有内容解析为列表列表,例如:

[[A, B, C], [D, E, F]]

为此,我尝试了以下操作:

import           Control.Monad
import           Text.ParserCombinators.Parsec
import           Text.ParserCombinators.Parsec.Language
import qualified Text.ParserCombinators.Parsec.Token    as P

parserP :: Parser [[MyType]]
parserP = do
  x  <- rowP
  xs <- many (newline >> rowP)
  return (x : xs)

rowP :: Parser [MyType]
rowP = manyTill cellP $ void newline <|> eof

cellP :: Parser (Cell Color)
cellP = aP <|> bP <|> ... -- rest of the parsers, they all look very similar

aP :: Parser MyType
aP = symbol "a" >> return A

bP :: Parser MyType
bP = symbol "b" >> return B

lexer = P.makeTokenParser emptyDef
symbol  = P.symbol lexer

但它无法 return 多个内部列表。相反,我得到的是:

[[A, B, C, D, E, F]]

我做错了什么?我期待 manyTill 解析 cellP 直到换行符,但事实并非如此。

解析器组合器对于这么简单的东西来说太过分了。我会使用 lines :: String -> [String] and words :: String -> [String] 来分解输入,然后将各个标记映射到 MyTypes.

toMyType :: String -> Maybe MyType
toMyType "a" = Just A
toMyType "b" = Just B
toMyType "c" = Just C
toMyType _ = Nothing

parseMyType :: String -> Maybe [[MyType]]
parseMyType = traverse (traverse toMyType) . fmap words . lines

你是对的,manyTill 一直解析到换行符。但是 manyTill 永远看不到换行符,因为 cellP 太急切了。 cellP 最终调用 P.symbol,其文档说明

symbol :: String -> ParsecT s u m String

Lexeme parser symbol s parses string s and skips trailing white space.

那里的关键词是'white space'。事实证明,Parsec 将 whitespace 定义为任何满足 isSpace 的字符,其中包括换行符。所以 P.symbol 很高兴地使用 c,接着是 space 和换行符,然后 manyTill 看起来并没有看到换行符,因为它是 已经消耗.

如果您想放弃 Parsec 例程,请使用 Benjamin 的解决方案。但是如果你决定坚持下去,基本的想法是你想修改语言的 whiteSpace 字段以正确定义 whitespace 不是换行符。像

lexer = let lexer0 = P.makeTokenParser emptyDef
        in lexer0 { whiteSpace = void $ many (oneOf " \t") }

那是伪代码,可能不适用于您的特定情况,但想法是存在的。您想要将 whiteSpace 的定义更改为您想要定义为 whiteSpace 的任何内容,而不是系统默认定义的内容。请注意,更改此设置也会破坏您的评论语法(如果您已定义的话),因为 whiteSpace 之前已具备处理评论的能力。

简而言之,本杰明的回答可能是最好的选择。这里没有真正的理由使用 Parsec。但了解 为什么 这个特定解决方案不起作用也很有帮助:Parsec 对语言的默认定义并非旨在处理具有重要性的换行符。