Parsing 如何使用Haskell解析器解析任意列表?
是否可以使用其中一个解析库(例如,Parsing 如何使用Haskell解析器解析任意列表?,parsing,haskell,parsec,Parsing,Haskell,Parsec,是否可以使用其中一个解析库(例如,Parsec)来解析与字符串不同的内容?我该怎么做 为了简单起见,我们假设输入是一个Int[Int]列表。任务可能是 删除前导零 将其余部分解析为模式(S+L+)*,其中S是小于10的数字,L是大于或等于10的数字 返回元组列表(Int,Int),其中fst是S的乘积,snd是L整数的乘积 如果有人能展示如何编写这样一个解析器(或类似的东西),那就太好了。很可能有一种方法可以让Parsec使用[a]作为流类型,但是解析器组合器背后的思想其实非常简单,而且使用
Parsec
)来解析与字符串不同的内容?我该怎么做
为了简单起见,我们假设输入是一个Int[Int]
列表。任务可能是
- 删除前导零
- 将其余部分解析为模式
,其中(S+L+)*
是小于10的数字,S
是大于或等于10的数字L
- 返回元组列表
,其中(Int,Int)
是fst
的乘积,S
是snd
整数的乘积L
如果有人能展示如何编写这样一个解析器(或类似的东西),那就太好了。很可能有一种方法可以让Parsec使用
[a]
作为流类型,但是解析器组合器背后的思想其实非常简单,而且使用您自己的库并不困难
我推荐格雷厄姆·哈顿(Graham Hutton)和埃里克·梅杰(Erik Meijer)提供的一个非常容易获得的资源
事实上,现在Erik Meijer正在edx.org上教授Haskell/functional programming入门课程,第7课是关于函数解析器的。正如他在讲座介绍中所说:
“…没有人能够在不编写自己的解析器组合器库的情况下掌握函数式编程。我们首先解释什么是解析器,以及它们如何自然地被视为副作用函数。接下来,我们定义了一些基本解析器和用于组合解析器的高阶函数…”
是的,正如user5402指出的,
Parsec
可以解析流的任何实例,包括任意列表。由于没有预定义的令牌解析器(就像文本解析器一样),您必须使用例如
我唯一觉得有点尴尬的是处理“源位置”SourcePos
是一种抽象类型(而不是类型类),它迫使我使用它的“filename/line/column”格式,这在这里感觉有点不自然
无论如何,下面是代码(为了简洁起见,不跳过前导零)
请注意错误消息中的行/列格式
当然,我们可以编写一个函数sanitiseSourcePos::SourcePos->MyListPosition
import Text.Parsec
myToken :: (Show a) => (a -> Bool) -> Parsec [a] () a
myToken test = tokenPrim show incPos $ justIf test where
incPos pos _ _ = incSourceColumn pos 1
justIf test x = if (test x) then Just x else Nothing
small = myToken (< 10)
large = myToken (>= 10)
smallLargePattern = do
smallints <- many1 small
largeints <- many1 large
let prod = foldl1 (*)
return (prod smallints, prod largeints)
myIntListParser :: Parsec [Int] () [(Int,Int)]
myIntListParser = many smallLargePattern
testMe :: [Int] -> [(Int, Int)]
testMe xs = case parse myIntListParser "your list" xs of
Left err -> error $ show err
Right result -> result
*Main> testMe [1,2,55,33,3,5,99]
[(2,1815),(15,99)]
*Main> testMe [1,2,55,33,3,5,99,1]
*** Exception: "your list" (line 1, column 9):
unexpected end of input