【问题标题】:Modify a class with typed traits in Scala在 Scala 中修改具有类型特征的类
【发布时间】:2013-06-01 05:50:02
【问题描述】:

我最近一直在玩 Scala,在使用解析器组合器时,我在扩展它们时遇到了一些问题。基本上,我想做的就是这样。

import scala.util.parsing.combinator.RegexParsers

abstract class Statement

case object Foo extends Statement
case object Bar extends Statement
case object Baz extends Statement

class Program(statements: List[Statement])

class FooBarLanguageParser extends RegexParsers {
  def program: Parser[Program] = rep(statement) ^^ (v => new Program(List() ++ v))
  def statement: Parser[Statement] = foo|bar
  def foo: Parser[Statement] = "foo" ^^ (_ => Foo)
  def bar: Parser[Statement] = "bar" ^^ (_ => Bar)
}

trait BazStatement { this: FooBarLanguageParser =>
  override def statement: Parser[Statement] = baz|this.statement  // inifinite recursion
  def baz: Parser[Statement] = "baz" ^^ (_ => Baz)
}

object Main {
  def main(args: Array[String]) {
    val normalFooBar = new FooBarLanguageParser()
    val fooBarProgram = normalFooBar.parseAll(normalFooBar.program, "foo bar")
    val extendedFooBar = new FooBarLanguageParser() with BazStatement
    val extendedFooBarProgram = extendedFooBar.parseAll(extendedFooBar.program,
       "foo bar baz")
    println(fooBarProgram.successful)
    println(extendedFooBarProgram.successful)
  }
}

这里,我想在BazStatement中调用FooBarLanguageParserstatement方法,但是使用上面的代码我递归调用BazStatement的方法,所以它无法正常工作。

我已经看过周围的答案,我知道我可以扩展类并使用抽象覆盖,或者像这样的想法,但我认为这在这里没有任何意义,就像BazStatement确实是我想与我的基本解析器混合的附加功能。我绝对不想有一些随机的东西,比如

object StrangeInheritance extends BazStatement

在代码中授权。

是否有任何惯用的方式在 Scala 中正确执行此操作,还是我需要重新考虑应用程序的总体设计?

【问题讨论】:

    标签: scala typetraits parser-combinators


    【解决方案1】:

    使用 super 调用 supertype 的方法,也使用 traits 定义顶层抽象。这个运行正常:

    import scala.util.parsing.combinator.RegexParsers
    
    abstract class Statement
    
    case object Foo extends Statement
    case object Bar extends Statement
    case object Baz extends Statement
    
    class Program(statements: List[Statement])
    
    trait FooBarLanguageParser extends RegexParsers {
      def program: Parser[Program] = rep(statement) ^^ (v => new Program(List() ++ v))
      def statement: Parser[Statement] = foo|bar
      def foo: Parser[Statement] = "foo" ^^ (_ => Foo)
      def bar: Parser[Statement] = "bar" ^^ (_ => Bar)
    }
    
    trait BazStatement extends FooBarLanguageParser {
      override def statement: Parser[Statement] = baz| super.statement  // inifinite recursion
      def baz: Parser[Statement] = "baz" ^^ (_ => Baz)
    }
    
    object Main {
      def main(args: Array[String]) {
        val normalFooBar = new FooBarLanguageParser() {}
        val fooBarProgram = normalFooBar.parseAll(normalFooBar.program, "foo bar")
        val extendedFooBar = new FooBarLanguageParser() with BazStatement
        val extendedFooBarProgram = extendedFooBar.parseAll(extendedFooBar.program,
           "foo bar baz")
        println(fooBarProgram.successful)
        println(extendedFooBarProgram.successful)
      }
    }
    

    【讨论】:

    • 抱歉,回答迟了。这段代码的问题是object FooBar extends BazStatement 可以完美运行,我可以使用FooBarLanguageParser 中的所有方法,我觉得这有点不妥,因为我希望BazStatement 成为我的@987654325 的一个额外功能@.
    • 实际上 mixins (traits) 是非常惯用的 scala 方式,它提供了特别的模块化。如果您想提供一种将一组谨慎的行为组合到一个运行时对象中的方法,我认为这是默认选项。您可能是对的,确实 mixins 在这里可能不起作用,因为很难以可扩展的方式设计您的顶级解析器。也许在某些实用程序特征中具有一组通用规则,然后在此“通用规则”特征的帮助下构建您的“具体”底部解析器,这将是一个比尝试使用继承更好的选择。
    • 感谢您的回答。我想我会像你说的那样使用定义一般规则和一些具体实现的顶级特征。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-05
    • 1970-01-01
    • 2016-11-26
    • 2011-05-14
    • 2012-10-22
    相关资源
    最近更新 更多