不能计算出一个解析器的最小长度 - 在Haskell UU-parsinglib

问题描述:

让我们来看看代码片段:不能计算出一个解析器的最小长度 - 在Haskell UU-parsinglib

pSegmentBegin p i = pIndentExact i *> ((:) <$> p i <*> ((pEOL *> pSegment p i) <|> pure [])) 

,如果我在我的解析器更改此代码:

pSegmentBegin p i = do 
    pIndentExact i 
    ((:) <$> p i <*> ((pEOL *> pSegment p i) <|> pure [])) 

我有一个错误:

canot compute minmal length of a parser due to occurrence of a moadic bind, use addLength to override 

我认为上面的解析器应该表现相同的方式。为什么会出现这个错误?

编辑

上面的例子是非常简单的(为了简化问题)和它下面的说明是没有必要使用这里做记号,但我想它使用的实际情况如下:

pSegmentBegin p i = do 
    j <- pIndentAtLast i 
    (:) <$> p j <*> ((pEOL *> pSegments p j) <|> pure []) 

我已经注意到了,做的声明之前加入“addLength 1”解决了这个问题,但我不能确定它是否正确的解决方案:

pSegmentBegin p i = addLength 2 $ do 
    j <- pIndentAtLast i 
    (:) <$> p j <*> ((pEOL *> pSegments p j) <|> pure []) 

正如我已经提到的许多时候应尽可能避免monadic接口。让我试着解释为什么应用接口是首选。

我的图书馆的一个显着特点是它通过插入或删除问题来执行纠错。当然,我们可以在这里采取一个超前的预见,但这会使这个过程非常昂贵。所以我们只采取三步有限展望。

现在假设我们要插入一个表达和表达的备选方案之一是:

EXPR:=“如果” expr的“然后” expr的“其他” EXPR

那么我们要排除这种替代因为选择这种替代方案需要插入另一个表达式等等。因此,我们对替代方案进行抽象解释,并确保在抽签的情况下(即有限预测的等价成本),我们采用非递归替代方案之一。

不幸的是,当一个人写一元语法分析器时,这个方案崩溃了,因为绑定右边的长度可能取决于左边的结果。因此,我们发出错误消息,并要求程序员提供一些帮助,以指示此替代方案可能消耗的令牌数量。实际值并不重要,只要你没有为递归的东西提供有限的长度并且可能导致无限的插入。它仅用于在插入的情况下选择最短的替代方案。

这个抽象的解释有一定的成本,如果你写在单子风格你所有的解析器是不可避免的,这种分析被重复过的一遍又一遍。所以:如果使用这个库,如果有一个适用的替代方法,请不要使用单色风格的PARSERS。

+0

谢谢!它澄清了很多。我认为在我的情况下,我必须使用monadic样式解析器组合器('pSegmentBegin'消耗空间,计算新的缩进级别,然后强制下面的所有行使用此缩进),所以不可能将其写入“纯应用程序“风格 –

+1

根据你对'StackOverflow'的问题 - 我不知道是否有任何问题可供认购 - 如果有,是迄今为止我还没有使用它,但我认为,在这里张贴问题,是很不错的主意 - 当我搜索关于'uu-parsinglib'的任何事情 - 我发现的唯一结果就是'StackOverflow',另外还有很多程序员使用它 - 它比任何邮件列表都更容易访问。 –

+0

Hi @Doaitse!您可以通过将标签悬停在标签上并点击“订阅”来获取包含[tag:uu-parsinglib]标签的所有未来SO问题的电子邮件通知。我会编辑你的问题来清理不相关的问题,并加深思考:)一切顺利。 – ulidtko

它试图静态分析需要读取多少输入以优化性能,但这种优化需要一个静态已知的解析器结构 - 可以由Applicative构建的类型,因为解析器效果不能依赖于解析器值如(>>=)所做的。

所以这就是错误的 - 当您使用do表示法时,它会转换为Monadic绑定,从而打破Applicative预测器。如果库只暴露了两个接口中的一个接口,这样就不会发生这种错误,但如果在同一个解析器中同时使用这两个接口,则会有一些不一致。

由于这种使用do是严格不必要的 - 您不会使用monadic界面提供给您的额外功率 - 最好避免使用它。

+1

是不是'(>>)'和'(*>)'应该是相等的? – 2013-08-16 16:55:20

+1

有一个不成文的规则,'Applicative'和'Monad'情况下应该匹配,否则事情会比较混乱(如这里),但如果你使用,你可以在'得到Applicative'的'性能Monad'那么它可以写一个'Applicative'实例,不能有'Monad'。 –

+0

它会成为一个书面的规则[当每一个'Monad'变得'Applicative'(http://www.reddit.com/r/haskell/comments/1k3fq7/what_are_some_killer_libraries_and_frameworks/cbl4d8r)。你可以*证明*(*)'和*(*>)'的默认绑定是等价的,只使用单子法则和在假设'ap =()'的假设下。 – 2013-08-16 19:18:39

我有一种变通方法我在uuparsinglib单子解析器使用。它是一种自我的答案在这里: Monadic parse with uu-parsinglib

您可能会发现它很有用