【问题标题】:When to use scala triple caret (^^^) vs double caret (^^) and the into method (>>)何时使用 scala 三重插入符号 (^^^) 与双插入符号 (^^) 和 into 方法 (>>)
【发布时间】:2014-01-21 13:25:06
【问题描述】:

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

【问题讨论】:

    标签: scala parser-combinators


    【解决方案1】:

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

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

    Option 是一元的,这意味着(部分)我们可以在其内容上使用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 是一元的这一事实也意味着我们可以将一个函数应用于Option[A],该函数接受一个A 并返回一个Option[B] 并得到一个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
    

    这都与您的问题相关,因为Parser 也是一元的,它具有mapflatMap 方法,它们的工作方式与Option 上的方法非常相似。它还有一堆令人困惑的运算符(I've ranted about before),包括你提到的那些,这些运算符只是mapflatMap 的别名:

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

    每个解析器的行为方式与上面的 Option 示例之一等效。

    【讨论】:

    • 完美!简短,简洁,务实和中肯的答案!非常感谢!
    • 再次感谢您的简洁回答!尽管我知道 Scala 的优势之一是它的简洁性,至少与 Java 相比,在编写 Parsers 时是否完全有必要使用这些插入符号,或者开发人员可以编写“长手”映射引用(我在我的自己的代码,只是为了可读性)?我假设编译器会优化并生成等效代码,对吧?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-03
    相关资源
    最近更新 更多