Scala组合器解析器,>>是什么意思?

时间:2011-11-02 10:55:05

标签: parsing scala parser-combinators

我对“>>”有点困惑在斯卡拉。 Daniel在Scala parser combinators parsing xml?中说它可以用来根据前一个解析器的结果来参数化解析器。有人可以给我一些例子/提示吗?我已经阅读了scaladoc但仍然不理解它。

感谢

2 个答案:

答案 0 :(得分:16)

正如我所说,它用于参数化解析器,但让我们通过一个示例来说明它。

让我们从一个简单的解析器开始,用一个单词解析一个数字:

def numberAndWord = number ~ word
def number        = "\\d+".r
def word          = "\\w+".r

RegexParsers下,这将解析“3个水果”等内容。

现在,假设您还想要列出这些“n事物”的内容。例如,“3种水果:香蕉,苹果,橙子”。让我们试着解析它是怎么回事。

首先,我如何解析“N”事?碰巧的是,有repN方法:

def threeThings = repN(3, word)

那将解析“香蕉苹果橙”,但不是“香蕉,苹果,橙子”。我需要一个分隔符。有repsep提供了,但这不会让我指定我想要多少次重复。所以,让我们自己提供分隔符:

def threeThings = word ~ repN(2, "," ~> word)

好的,那句话。我们现在可以写出整个例子,有三件事,比如:

def listOfThings = "3" ~ word ~ ":" ~ threeThings
def word         = "\\w+".r
def threeThings  = word ~ repN(2, "," ~> word)

那种作品,除了我在3中修正“N”。我想让用户指定多少。这就是>>的地方,也就是into(也就是flatMap的{​​{1}})。首先,让我们改变Parser

threeThings

这比你预期的要复杂一些,因为我强迫它返回def things(n: Int) = n match { case 1 => word ^^ (List(_)) case x if x > 1 => word ~ repN(x - 1, "," ~> word) ^^ { case w ~ l => w :: l } case x => err("Invalid repetitions: "+x) } 。但是如何将参数传递给事物呢?我的意思是,这不起作用:

Parser[List[String]]

但我们可以像这样重写:

def listOfThings = number ~ word ~ ":" ~ things(/* what do I put here?*/)

这几乎已经足够了,除了我现在丢失了def listOfThings = (number ~ word <~ ":") >> { case n ~ what => things(n.toInt) } n:它只返回“List(香蕉,苹果,橙色)”,而不是它应该有多少,以及什么他们是。我可以这样做:

what

最后评论。你可能想知道问自己“你是什么意思def listOfThings = (number ~ word <~ ":") >> { case n ~ what => things(n.toInt) ^^ { list => new ~(n.toInt, new ~(what, list)) } } def number = "\\d+".r def word = "\\w+".r def things(n: Int) = n match { case 1 => word ^^ (List(_)) case x if x > 1 => word ~ repN(x - 1, "," ~> word) ^^ { case w ~ l => w :: l } case x => err("Invalid repetitions: "+x) } ?这不是一个monad / for-comprehension thingy吗?”为什么,是的,是的! :-)这是写flatMap的另一种方式:

listOfThings

我没有def listOfThings = for { nOfWhat <- number ~ word <~ ":" n ~ what = nOfWhat list <- things(n.toInt) } yield new ~(n.toInt, new ~(what, list)) ,因为它在Scala中使用了n ~ what <- number ~ word <~ ":"filter,而withFilter没有实现。但是这里甚至是编写它的另一种方式,它没有完全相同的语义,但产生相同的结果:

Parsers

这甚至可能让人觉得可能声称​​“monad无处不在”可能有什么东西。 : - )

答案 1 :(得分:5)

方法>>接受一个函数,该函数被赋予解析器的结果并使用它来构造一个新的解析器。如上所述,这可以用于在先前解析器的结果上参数化解析器。

实施例

以下解析器使用n + 1整数值解析一行。第一个值n表示要遵循的值的数量。解析第一个整数,然后使用此解析的结果构造一个解析n进一步整数的解析器。

分析器定义

以下行假定您可以使用parseInt: Parser[Int]解析整数。它首先解析整数值n,然后使用>>来解析构成解析器结果的其他整数n。因此解析器不返回初始n(尽管它是返回列表的大小)。

def intLine: Parser[Seq[Int]] = parseInt >> (n => repN(n,parseInt))

有效输入

1 42
3 1 2 3
0

输入无效

0 1
1
3 42 42