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

Tg.*_*Tg. 5 parsing scala parser-combinators

我对scala中的">>"有点困惑.Daniel在解析xml的Scala解析器组合器中说道它可以用于根据先前解析器的结果参数化解析器.有人可以给我一些例子/提示吗?我已经读过scaladoc但仍然不理解它.

谢谢

Dan*_*ral 16

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

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

def numberAndWord = number ~ word
def number        = "\\d+".r
def word          = "\\w+".r
Run Code Online (Sandbox Code Playgroud)

RegexParsers下,这将解析像"3个水果"之类的东西.

现在,让我们说你也想要列出这些"n事物"的内容.例如,"3种水果:香蕉,苹果,橙子".让我们试着解析一下它是怎么回事.

首先,我如何解析"N"的东西?碰巧,有一种repN方法:

def threeThings = repN(3, word)
Run Code Online (Sandbox Code Playgroud)

这将解析"香蕉苹果橙",但不是"香蕉,苹果,橙".我需要一个分隔符.有repsep这样的提供,但这不会让我指定我想要多少重复.那么,让我们自己提供分隔符:

def threeThings = word ~ repN(2, "," ~> word)
Run Code Online (Sandbox Code Playgroud)

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

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

这种工作,除了我在3中修复"N".我想让用户指定多少.而这也正是>>,也被称为into(是的,它是flatMapParser),进入.首先,让我们改变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)
}
Run Code Online (Sandbox Code Playgroud)

这比你想象的要复杂一点,因为我强迫它返回Parser[List[String]].但是如何将参数传递给事物呢?我的意思是,这不起作用:

def listOfThings = number ~ word ~ ":" ~ things(/* what do I put here?*/)
Run Code Online (Sandbox Code Playgroud)

但我们可以像这样重写:

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

这几乎是不够好,但我现在已经失去了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)
}
Run Code Online (Sandbox Code Playgroud)

只是最后的评论.你可能想知道问自己"你的意思flatMap是什么?这不是一个monad/for-comprehension thingy吗?" 为什么,是的,是的!:-)这是另一种写作方式listOfThings:

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

我不这样做n ~ what <- number ~ word <~ ":",因为使用filterwithFilterScala中,这是不被执行Parsers.但这里甚至是编写它的另一种方式,它没有完全相同的语义,但产生相同的结果:

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

这甚至可能让人觉得可能"monad无处不在"的说法可能会有所帮助.:-)

  • @Tg.这正是这里发生的事情.使用`~`运算符解析某些内容时,结果将是[`~`class]的实例(http://www.scala-lang.org/api/current/index.html#scala.util. parsing.combinator.Parsers $$波浪号).我可以 - 可以说,我应该 - 返回一个元组 - 它更容易.但是,我想在示例代码中保留原始返回值. (2认同)

zig*_*tar 5

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

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

解析器定义

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

def intLine: Parser[Seq[Int]] = parseInt >> (n => repN(n,parseInt))
Run Code Online (Sandbox Code Playgroud)

有效输入

1 42
3 1 2 3
0
Run Code Online (Sandbox Code Playgroud)

输入无效

0 1
1
3 42 42
Run Code Online (Sandbox Code Playgroud)