2011-12-27 30 views
1

我正在将一些代码从attoparsec转换为Parsec,因为解析器需要生成更好的错误消息。 attoparsec代码广泛使用inClass(和notInClass)。 Parsec有没有类似的功能,可以让我机械地翻译inClass -cure? Hayoo和Hoogle没有提供任何有关此事的见解。Parsec中attoparsecs`inClass`的等效

inClass :: String -> Char -> Bool 

inClass "a-c'-)0-3-"相当于\ x -> elem x "abc'()0123-",但后者是低效的和繁琐写为大范围。

如果没有其他东西可用,我将自己重新实现该函数。

回答

1

没有任何这样的组合器;如果有的话,它将在Text.Parsec.Char(这是定义涉及Char的所有标准解析器组合函数的地方)。你应该可以很容易地定义它。

虽然我不认为你可以在toptopc上获得相同的性能优势,它依赖于内部FastSet类型,它仅适用于8位字符。当然,如果你不需要Unicode支持,这可能不是问题,但code for FastSet意味着你会得到不可预知的结果,传递的字符数大于'\255',所以如果你想重新使用基于FastSet的解决方案,你会至少必须读取您在binary mode中解析的字符串。 (您还可以到FastSet执行复制到你的程序,因为它不出口......)

如果你的范围字符串是短,那么像这样一个简单的解决方案很可能是相当快:

type Range = (Char, Char) 

inClass :: String -> Char -> Bool 
inClass = inClass' . parseClass 

parseClass :: String -> [Range] 
parseClass "" = [] 
parseClass (a:'-':b:xs) = (a, b) : parseClass xs 
parseClass (x:xs) = (x, x) : parseClass xs 

inClass' :: [Range] -> Char -> Bool 
inClass' cls c = any (\(a,b) -> c >= a && c <= b) cls 

你甚至可以尝试这样的事情,这应该至少与上述版本(包括当为单个inClass s许多呼叫制造)作为高效,并且还避免了列表遍历开销:

inClass :: String -> Char -> Bool 
inClass "" = const False 
inClass (a:'-':b:xs) = \c -> (c >= a && c <= b) || f c where f = inClass xs 
inClass (x:xs) = \c -> c == x || f c where f = inClass xs 

(注意将递归移出的lambda;我不知道GHC是否可以自己做这件事。)

+0

这个问题并不是真的要求解决方案,我可能最终会为此写一个TH宏,但上面的代码解决了这个问题很好。 – dflemstr 2011-12-28 02:55:40

+0

我认为只要有效实施,我会增加一些价值,因为“对不起,对不起”对未来的访问者不是很有帮助:) – ehird 2011-12-28 03:11:47

1

不,在parsec中没有等价物。你必须自己写。我看到两个主要选择,

  1. 解析inClass语法来创建它String,与oneOf
  2. 使用解析它创建一个函数传递给satisfy

前者是当然是后者的一个特例,如果你的班级范围较大,效率会降低。但实施起来可能更容易一些。

(|||) :: (a -> Bool) -> (a -> Bool) -> a -> Bool 
p ||| q = \x -> p x || q x 
(&&&) :: (a -> Bool) -> (a -> Bool) -> a -> Bool 
p &&& q = \x -> p x && q x 

parseClass (l:'-':h:more) = ((>= l) &&& (<= h)) ||| parseClass more 
parseClass (c:cs) = (== c) ||| parseClass cs 
parseClass [] = const False 

是一种简单的可能性。