首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解trifecta解析器<|>并尝试

理解trifecta解析器<|>并尝试
EN

Stack Overflow用户
提问于 2021-09-07 20:49:27
回答 1查看 139关注 0票数 1

当我读Haskell的书时,我偶然发现了三联

我正试着把头转过来,但还是不能理解<|>

我有以下几个问题.

简单的单词(<|>) =一元选择?

p =a <|> b --使用解析器a如果不是那么使用b?

如果是,那么为什么下面的解析器失败了?

代码语言:javascript
复制
parseFraction :: Parser Rational
parseFraction = do
    numerator <- decimal
    char '/'
    denominator <- decimal
    case denominator of 
        0 -> fail "denominator cannot be zero"
        _ -> return (numerator % denominator)


type RationalOrDecimal = Either Rational Integer
parseRationalOrDecimal = (Left <$> parseFraction) <|> (Right<$> decimal)


main = do
    let p f i = parseString f mempty i
    print $ p (some (skipMany (oneOf "\n")  *> parseRationalOrDecimal <* skipMany (oneOf "\n"))) "10"

在完美世界中,如果a is parseFraction将要失败,那么<|>应该使用十进制,但事实并非如此。但是当我使用“尝试”的时候,它是有效的。

  1. 我错过了什么?
  2. 为什么我们需要在<|>在第一次失败时运行第二个解析器时使用try?

parseRationalOrDecimal = try (Left <$> parseFraction) <|> (Right<$> decimal)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-09-08 09:52:59

原因是由于parseFraction在失败之前消耗了输入,因此被认为是选择中的正确分支。让我给你举个例子:

假设您正在编写python解析器,您必须决定声明是class还是函数(关键字def),然后编写

代码语言:javascript
复制
parseExpresion = word "def" <|> word "class" -- DISCLAIMER: using a ficticious library

然后,如果用户写入defclass,它将匹配,但如果用户写入det,它将尝试第一个分支并匹配de,然后由于找到t而无法匹配预期的f。它不会费心尝试下一个解析器,因为错误被认为是在第一个分支中。尝试class解析器没有什么意义,因为错误可能在第一个分支中。

在您的示例中,parseFraction匹配一些数字,然后由于找不到/而失败,然后它就不用去尝试decimal解析器了。

这是一个设计决策,其他一些库使用不同的约定(例如:Attoparsec总是在失败时回溯),有些函数声称“不使用输入”(例如:notFollowedBy)

请注意,这里有一个折衷方案:

First:如果<|>的行为与您预期的一样,则如下所示

代码语言:javascript
复制
parse parseRationalOrDecimal "123456789A"

首先解析所有数字直到找到"A“,然后再解析所有数字直到找到"A”为止.所以,做同样的计算两次,只是为了返回一个失败。

第二个:如果您更关心错误消息,那么当前的行为就更方便了。按照python的例子,想象一下:

代码语言:javascript
复制
parseExpresion = word "def" <|> word "class" <|> word "import" <|> word "type" <|> word "from"

如果用户键入"frmo“,解析器将转到最后一个分支,并引发类似于expected "from" but "frmo" was found的错误,而如果必须检查所有选项,则错误将更像expected one of "def", "class", "import", "type" of "from",与实际的错误类型不太接近。

正如我所说的,这是一个库设计决定,我只是想让您相信,有充分的理由不自动尝试所有的替代方案,如果您明确地想要这样做,那么就使用try

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69094408

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档