2

我正在尝试解析标志的排列。我想要的行为是“任何顺序的一个或多个标志,不重复”。我正在使用以下软件包:

  • 兆秒差距
  • 解析器组合器

我拥有的代码正在输出我想要的,但对输入过于宽松。我不明白为什么它接受多个相同的标志。我在这里做错了什么?

pFlags :: Parser [Flag]
pFlags = runPermutation $ f <$> 
    toPermutation (optional (GroupFlag <$ char '\'')) <*> 
    toPermutation (optional (LeftJustifyFlag <$ char '-'))
    where f a b = catMaybes [a, b]

例子:

"'-" = [GroupFlag, LeftJustifyFlag] -- CORRECT
"-'" = [LeftJustifyFlag, GroupFlag] -- CORRECT
"''''-" = [GroupFlag, LeftJustifyFlag] -- INCORRECT, should fail if there's more than one of the same flag.
4

1 回答 1

2

而不是toPermutationwith optional,我相信你需要使用toPermutationWithDefault,像这样的东西(未经测试):

toPermutationWithDefault Nothing (Just GroupFlag <$ char '\'')

原因在论文“Parsing Permutation Phrases”(PDF)第 4 节“添加可选元素”(emph. added)中进行了描述:

例如,考虑 [...] abc的所有排列。假设b可以是空的,我们想要识别ac。这可以通过三种不同的方式完成,因为可以在 a 之前a之后或c之后识别空b幸运的是,它与空b的解析结果无关是派生的,因为顺序并不重要。这允许我们使用类似于 Cameron 提出的策略:解析看到的非空成分,如果所有剩余元素都是可选的,则允许解析器停止。当解析器停止时,将为所有未被识别的可选元素返回默认值。

为了实现这个策略,我们需要能够确定解析器是否可以派生空字符串并将其拆分为默认值和非空部分,即除了不识别空字符串之外行为相同的解析器。

也就是说,置换解析器需要知道哪些元素可以在不消耗输入的情况下成功,否则它会太急于提交到分支。不过,我不知道为什么这会导致接受元素的倍数;也许您还缺少一个eof

于 2021-12-18T20:00:16.420 回答