何时使用 scala 三重插入符 (^^^) 与双重插入符 (^^) 和 into 方法 (>>) [英] When to use scala triple caret (^^^) vs double caret (^^) and the into method (>>)
问题描述
有人可以解释在设计 Scala 解析器组合器时如何以及何时使用三重插入符号 ^^^(与双插入符号 ^^)?以及何时/如何使用 parser.into() 方法 (>>).
Can someone explain how and when to use the triple caret ^^^ (vs the double caret ^^) when designing scala parser combinators? And also when / how to use the parser.into() method (>>).
推荐答案
我将从一个使用 Scala 的 Option
类型的示例开始,它在一些重要方面类似于 Parser
代码>,但可以更容易推理.假设我们有以下两个值:
I'll begin with an example using Scala's Option
type, which is similar in some important ways to Parser
, but can be easier to reason about. Suppose we have the following two values:
val fullBox: Option[String] = Some("13")
val emptyBox: Option[String] = None
Option
是 monadic,这意味着(部分)我们可以map
一个函数覆盖其内容:
Option
is monadic, which means (in part) that we can map
a function over its contents:
scala> fullBox.map(_.length)
res0: Option[Int] = Some(2)
scala> emptyBox.map(_.length)
res1: Option[Int] = None
只关心 Option
是否已满的情况并不少见,在这种情况下,我们可以将 map
与忽略其参数的函数一起使用:
It's not uncommon to care only about whether the Option
is full or not, in which case we can use map
with a function that ignores its argument:
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]
并得到一个 Option[B]
.在这个例子中,我将使用一个尝试将字符串解析为整数的函数:
The fact that Option
is monadic also means that we can apply to an Option[A]
a function that takes an A
and returns an Option[B]
and get an Option[B]
. For this example I'll use a function that attempts to parse a string into an integer:
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
这都与您的问题有关,因为 Parser
也是 monadic,它具有以非常相似的方式工作的 map
和 flatMap
方法到 Option
上的那些.它还有一堆令人困惑的操作符(我之前已经吐槽过),包括你提到的那些,以及这些运算符只是 map
和 flatMap
的别名:
This is all relevant to your question because Parser
is also monadic, and it has map
and flatMap
methods that work in very similar ways to the ones on Option
. It also has a bunch of confusing operators (which I've ranted about before), including the ones you mention, and these operators are just aliases for map
and flatMap
:
(parser ^^ transformation) == parser.map(transformation)
(parser ^^^ replacement) == parser.map(_ => replacement)
(parser >> nextStep) == parser.flatMap(nextStep)
例如,您可以编写以下内容:
So for example you could write the following:
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
}
其中每个解析器的行为方式与上面的 Option
示例中的一个相同.
Where each parser behaves in a way that's equivalent to one of the Option
examples above.
这篇关于何时使用 scala 三重插入符 (^^^) 与双重插入符 (^^) 和 into 方法 (>>)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!