- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
问题
我知道Parsec
和 uu-parsinglib
我已经在他们两个中编写了解析器。最近发现uu-parsinglib
有问题,这可能会显着影响其性能,我看不到解决方法。
让我们考虑以下 Parsec 解析器:
pa = char 'a'
pb = char 'b'
pTest = many $ try(pa <* pb)
uu-parsinglib
中的等价物是什么? ?它会
不是 如下:
pa = pSym 'a'
pb = pSym 'b'
pTest = pList_ng (pa <* pb)
Parsec
,
many
会吃
(pa <* pb)
(成对的
"ab"
)贪婪直到不再匹配,而在
uu-parsinglib
,
pList_ng
不是贪心的,所以它会在解析每个
(pa <* pb)
后将可能的回溯方式保存在内存中.
pList(try(pa <* pb))
在
uu-parsinglib
?
pExample = pTest <* (pa <* pb)
"ababab"
的样本输入.
Parsec
,我们会得到错误(因为
pTest
是
"ab"
的贪婪解析对),但在
uu-parsinglib
,字符串将被解析没有问题。
pList_ng
切换至
pList
, 因为它不等于
Parsec
版本。例如:
pExample2 = pTest <* pa
"ababa"
的样本输入会在
Parsec
中取得成功,但在
uu-parsinglib
中失败, 使用贪心时
pList
.
uu-parsinglib
如果我们使用
pList_ng
将会成功在这里,但对于某些输入和规则可能会慢很多。例如,考虑输入
"ababab"
,
Parsec
只会失败,因为
pTest
将消耗整个字符串和
pa
不会匹配。
uu-parsinglib
也会失败,但检查更多步骤 - 它将匹配整个字符串并失败,然后丢弃最后一个
"ab"
配对并再次失败,等等。如果我们有一些嵌套规则和有趣的输入文本,它将生成
巨大的区别。
pattern = many("ab") + "a"
input = many(pattern)
uu-parsinglib
:
import Data.Char
import qualified Text.ParserCombinators.UU as UU
import Text.ParserCombinators.UU hiding(parse)
import Text.ParserCombinators.UU.BasicInstances hiding (Parser)
import System.TimeIt (timeIt)
pa = pSym 'a'
pb = pSym 'b'
pTest = pList $ pList_ng ((\x y -> [x,y]) <$> pa <*> pb) <* pa
main :: IO ()
main = do
timeIt maininner
return ()
maininner = do
let (x,e) = UU.parse ((,) <$> pTest <*> pEnd) (createStr (LineColPos 0 0 0) (concat $ replicate 1000 (concat (replicate 1000 "ab") ++ "a")))
print $ length x
Parsec
:
import Control.Applicative
import Text.Parsec hiding (many, optional, parse, (<|>))
import qualified Text.Parsec as Parsec
import System.TimeIt (timeIt)
pa = char 'a'
pb = char 'b'
pTest = many $ many (try ((\x y -> [x,y]) <$> pa <*> pb)) <* pa
main :: IO ()
main = do
timeIt maininner2
return ()
maininner2 = do
let Right x = Parsec.runParser pTest (0::Int) "test" $ (concat $ replicate 1000 (concat (replicate 1000 "ab") ++ "a"))
print $ length x
uu-parsinglib
是
> 300% 慢 :
uu-parsinglib - 3.19s
Parsec - 1.04s
ghc -O3
标志编译)
最佳答案
要了解其中的微妙之处,重要的是要了解 Haskell 中的 try 构造与 uu-parsinglib 中使用的非贪婪解析策略之间的区别。实际上,后者是一种仅向前看一个符号的尝试。在这方面,它不如 Parsec 中的 try 构造强大,后者指定特定构造必须完全存在。然后是潜在的不同整体策略。 Parsec 使用带有显式尝试提交的回溯策略,而 uu-parsinglib 使用带有偶尔单个符号前瞻的广度优先策略。
因此,两者之间存在时差也就不足为奇了。在 Parsec 案例中,在看到完整的构造(两个符号)之后,决定尝试的替代方案确实适用,而贪婪的 uu-parsinglib 在成功看到第一个符号后决定这一定是正确的替代方案。而这个结论可能是不合理的。
如果一个人转向广度优先策略,uu-parsinglib 使用一个人必须同时跟踪几个备选方案,这需要时间。两次替代,两次时间等。
Parsec 的优势在于,您可以通过自由使用 try 构造和以正确的顺序放置备选方案来调整回溯解析器,但您也更有可能在邮件列表上询问为什么您的解析器无法按预期工作.你不是在写语法,而是写解析器。 uu-parsinglib 从光谱的另一端开始:我们尝试接受相当大的语法集合(以及它们所隐含的解析器)。
我的感觉也是,如果存在具有出色错误修复解析器的 try 构造,则要复杂得多。一旦一个 try 构造失败,就不可能回到那里并决定,通过一个小的修正,它比它之后的替代方案要好得多。
关于uu-parsinglib 的性能与 Parsec 中的 "try"相比,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20846429/
Haskell Parsec 的 indents 包提供了一种解析缩进式语言(如 Haskell 和 Python)的方法。它重新定义了 Parser类型,那么如何使用 Parsec 的 Text.P
我有一个用 Text 编写的解析器作为流类型,而默认为 Text.Parsec.String模块使用 String除此以外。 如何在 Parsec Text b c 的上下文中使用自定义编写的解析器
Text Text.Parsec Text.Parsec.ByteString Text.Parsec.ByteString.Lazy
我在弄清楚如何使用 Text.Parsec.Indent 中的任何功能时遇到问题 indents 提供的模块Haskell 的包,它是 Parsec 的一种附加组件。 所有这些功能有什么作用?它们将如
Text Text.Parsec Text.Parsec.ByteString Text.Parsec.ByteString.Lazy
我目前正在尝试使用现实世界 Haskell 中提供的完整 CSV 解析器。为了我尝试修改代码以使用 ByteString 而不是 String,但是有一个 string 组合器仅适用于 字符串。 是否
我正在尝试解析嵌套的类 C block 注释 import Text.ParserCombinators.Parsec import Control.Monad (liftM) flat :: Mon
如果违反语义规则,使用 Parsec 如何在特定位置指示错误。我知道通常我们不想做这样的事情,但考虑一下示例语法。 ::= | ... ::= a positive integer power
我目前正在尝试使用 Parsec 在 Haskell 中设计一个解析器。声明类型的语法应如下所示: Fruit is a Apple 类型也应该能够有参数: Fruit a b is a Apple
我写了这样的排列解析例子: data Entry = Entry { first_name :: String , last_name :: String , date_of_birt
我正在尝试解析(目前)Dot 语言的一个子集。 语法是here我的代码如下 import System.Environment import System.IO import qualified Te
我有一个列表,我需要解析除最后一个元素之外的所有元素都需要由一个解析器解析,最后一个元素需要由另一个解析器解析。 a = "p1 p1b ... p2" or a = "p2" 原来我试过 parse
我需要为一种编程语言创建一个解析器。到目前为止,它已经完成了 95%,我想说,除了一个小细节。 用这种语言编写的程序具有以下结构: outputs inputs expressions 要求是输出不能
在我的工作中,我遇到了很多粗糙的 sql,我有一个聪明的想法,那就是编写一个程序来解析 sql 并整齐地打印出来。我很快就完成了大部分工作,但遇到了一个我不知道如何解决的问题。 所以让我们假设 sql
我正在编写一种使用 Parsec 进行解析的编程语言。为了报告错误消息,我使用 getPosition 将语法树的每个元素都标记了其源位置。函数来自 the Pos module 秒差距。 但是,它只
我正在尝试使用 parsec 解析如下表达式: f a b c => (Appl (Appl (Appl f a) b) c) 我尝试使用以下内容: appl :: Parser Expr appl
是否有可能以某种方式获得某些自定义类型的解析错误?例如,从错误中获取更多关于解析上下文的信息会很酷。而且仅以短信的形式提供错误信息似乎不太方便。 最佳答案 正如 Rhymoid 所观察到的,不幸的是,
我对 Parsec 的一个常见问题是,如果无效输入出现在“正确”的位置,它往往会忽略它。 作为一个具体的例子,假设我们有 integer :: Parser Int ,我写 expression =
我正在使用 Parsec 解析表达式,并且我想使用 Parsec 中的用户状态来跟踪这些表达式中的变量。不幸的是,我真的不知道该怎么做。 给定以下代码: import Data.Set as Set
我正在尝试编写一个 Haksell Parsec Parser,它将文件中的输入数据解析为 LogLine 数据类型,如下所示: --Final parser that holds the indvi
我是一名优秀的程序员,十分优秀!