我正在将一些代码从attoparsec转换为Parsec,因为解析器需要生成更好的错误消息。 attoparsec代码广泛使用inClass
(和notInClass
)。 Parsec有类似的功能可以让我翻译inClass
- 机械地出现吗? Hayoo和Hoogle没有对此事提供任何见解。
inClass :: String -> Char -> Bool
inClass "a-c'-)0-3-"
等同于\ x -> elem x "abc'()0123-"
,但后者对于大范围编写效率低且乏味。
如果没有别的东西,我会自己重新实现这个功能。
答案 0 :(得分:1)
不,parsec中没有等价物。你必须自己写。我看到两个主要选项,
inClass
语法,从中创建String
,与oneOf
一起使用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
是一种笨笨的可能性。
答案 1 :(得分:1)
没有这样的组合器;如果存在,它将在Text.Parsec.Char中(这是定义涉及Char
的所有标准解析器组合函数的地方)。你应该能够很容易地定义它。
我认为你无法获得attoparsec与its implementation相同的性能优势;它依赖于内部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的递归 out ;我不知道GHC是否可以/将自己这样做。)