何时使用scala triple caret(^^^)vs双插入符号(^^)和into方法(>>)

时间:2014-01-21 13:25:06

标签: scala parser-combinators

在设计scala解析器组合器时,有人可以解释如何以及何时使用三重插入符^^^(vs双插入符号^^)?以及何时/如何使用parser.into()方法(>>)。

1 个答案:

答案 0 :(得分:16)

我将首先使用Scala的Option类型的示例,它在Parser的某些重要方面类似,但可以更容易推理。假设我们有以下两个值:

val fullBox: Option[String] = Some("13")
val emptyBox: Option[String] = None

Option是monadic,这意味着(部分)我们可以map对其内容执行一个函数:

scala> fullBox.map(_.length)
res0: Option[Int] = Some(2)

scala> emptyBox.map(_.length)
res1: Option[Int] = None

只关心Option是否已满,这种情况并不少见,在这种情况下,我们可以使用map来忽略其参数的函数:

scala> fullBox.map(_ => "Has a value!")
res2: Option[String] = Some(Has a value!)

scala> emptyBox.map(_ => "Has a value!")
res3: Option[String] = None

Option是monadic这一事实也意味着我们可以向Option[A]申请一个A并返回Option[B]并获得{{1}的函数}}。对于此示例,我将使用一个尝试将字符串解析为整数的函数:

Option[B]

现在我们可以写下以下内容:

def parseIntString(s: String): Option[Int] = try Some(s.toInt) catch {
  case _: Throwable => None
}

这与您的问题都相关,因为scala> fullBox.flatMap(parseIntString) res4: Option[Int] = Some(13) scala> emptyBox.flatMap(parseIntString) res5: Option[Int] = None scala> Some("not an integer").flatMap(parseIntString) res6: Option[Int] = None 也是一元的,并且Parsermap方法的工作方式与flatMap上的方法非常相似。它还有一堆令人困惑的运算符(I've ranted about before),包括你提到的运算符,这些运算符只是Optionmap的别名:

flatMap

例如,您可以编写以下内容:

(parser ^^ transformation) == parser.map(transformation)
(parser ^^^ replacement) == parser.map(_ => replacement)
(parser >> nextStep) == parser.flatMap(nextStep)

每个解析器的行为方式与上述object MyParser extends RegexParsers { def parseIntString(s: String) = try success(s.toInt) catch { case t: Throwable => err(t.getMessage) } val digits: Parser[String] = """\d+""".r val numberOfDigits: Parser[Int] = digits ^^ (_.length) val ifDigitsMessage: Parser[String] = digits ^^^ "Has a value!" val integer: Parser[Int] = digits >> parseIntString } 示例之一相同。