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

发布于 2024-12-13 04:28:07 字数 224 浏览 0 评论 0原文

我对“>>”有点困惑在斯卡拉。 Daniel 在 Scala 解析器组合器解析 xml? 中说它可以用于参数化解析器基于先前解析器的结果。有人能给我一些例子/提示吗?我已经读过 scaladoc 但仍然不明白。

谢谢

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

多情癖 2024-12-20 04:28:07

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

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

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

RegexParsers,这将解析“3 个水果”之类的内容。

现在,假设您还想要这些“n 件事”的列表。例如,“3种水果:香蕉、苹果、橙子”。让我们尝试解析它,看看它是如何进行的。

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

def threeThings = repN(3, word)

它将解析“banana apple Orange”,但不会解析“banana, apple, Orange”。我需要一个分隔符。有 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 (是的,它是 ParserflatMap ),进入。首先,让我们更改 thirdThings

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)
}

这几乎足够好了,除了我现在丢失了 nwhat:它只返回“列出(香蕉、苹果、橙子)”,而不是应该有多少,以及它们是什么。我可以这样做:

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?这不是一个 monad/用于理解的东西吗?”为什么,是的,是的! :-) 这是 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 <~ ":" 因为它使用 Scala 中的 filterwithFilter,它不是由 Parsers 实现的。但这里还有另一种编写方式,它不具有完全相同的语义,但会产生相同的结果:

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

这甚至可能让人认为“单子无处不在”的说法可能会有一些东西。 :-)

As I said, it serves to parameterize a parser, but let's walk through an example to make it clear.

Let's start with a simple parser, that parses a number follow by a word:

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

Under RegexParsers, this will parse stuff like "3 fruits".

Now, let's say you also want a list of what these "n things" are. For example, "3 fruits: banana, apple, orange". Let's try to parse that to see how it goes.

First, how do I parse "N" things? As it happen, there's a repN method:

def threeThings = repN(3, word)

That will parse "banana apple orange", but not "banana, apple, orange". I need a separator. There's repsep that provides that, but that won't let me specify how many repetitions I want. So, let's provide the separator ourselves:

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

Ok, that words. We can write the whole example now, for three things, like this:

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

That kind of works, except that I'm fixing "N" in 3. I want to let the user specify how many. And that's where >>, also known as into (and, yes, it is flatMap for Parser), comes into. First, let's change 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)
}

This is slightly more complicated than you might have expected, because I'm forcing it to return Parser[List[String]]. But how do I pass a parameter to things? I mean, this won't work:

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

But we can rewrite that like this:

def listOfThings = (number ~ word <~ ":") >> {
  case n ~ what => things(n.toInt)
}

That is almost good enough, except that I now lost n and what: it only returns "List(banana, apple, orange)", not how many there ought to be, and what they are. I can do that like this:

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)
}

Just a final comment. You might have wondered asked yourself "what do you mean flatMap? Isn't that a monad/for-comprehension thingy?" Why, yes, and yes! :-) Here's another way of writing listOfThings:

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

I'm not doing n ~ what <- number ~ word <~ ":" because that uses filter or withFilter in Scala, which is not implemented by Parsers. But here's even another way of writing it, that doesn't have the exact same semantics, but produce the same results:

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

This might even give one to think that maybe the claim that "monads are everywhere" might have something to it. :-)

反话 2024-12-20 04:28:07

方法>>采用一个函数,该函数给出解析器的结果,并使用它来构造一个新的解析器。如前所述,这可用于根据前一个解析器的结果对解析器进行参数化。

示例

以下解析器解析包含 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

The method >> takes a function that is given the result of the parser and uses it to contruct a new parser. As stated, this can be used to parameterize a parser on the result of a previous parser.

Example

The following parser parses a line with n + 1 integer values. The first value n states the number of values to follow. This first integer is parsed and then the result of this parse is used to construct a parser that parses n further integers.

Parser definition

The following line assumes, that you can parse an integer with parseInt: Parser[Int]. It first parses an integer value n and then uses >> to parse n additional integers which form the result of the parser. So the initial n is not returned by the parser (though it's the size of the returned list).

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

Valid inputs

1 42
3 1 2 3
0

Invalid inputs

0 1
1
3 42 42
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文