5

I am little bit confusing about ">>" in scala. Daniel said in Scala parser combinators parsing xml? that it could be used to parameterize the parser base on result from previous parser. Could someone give me some example/hint ? I already read scaladoc but still not understand it.

thanks

4

2 回答 2

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(而且,是的,它是flatMapfor 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并且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)
}

只是最后的评论。你可能想知道问自己“你是什么意思flatMap?这不是一个单子/理解的东西吗?” 为什么,是的,是的!:-) 这是另一种写作方式listOfThings

def listOfThings   = for {
  nOfWhat  <- number ~ word <~ ":"
  n ~ what = nOfWhat
  list     <- things(n.toInt)
}  yield new ~(n.toInt, new ~(what, list))

我不这样做n ~ what <- number ~ word <~ ":"是因为它使用了filterorwithFilter在 Scala 中,而Parsers. 但这里甚至还有另一种写法,它没有完全相同的语义,但产生相同的结果:

def listOfThings   = for {
  n    <- number
  what <- word
  _    <- ":" : Parser[String]
  list <- things(n.toInt)
}  yield new ~(n.toInt, new ~(what, list))

这甚至可能让人认为“单子无处不在”的说法可能有一定的意义。:-)

于 2011-11-02T17:54:53.070 回答
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
于 2011-11-02T11:50:53.770 回答