2013-06-01 24 views
0

最近我一直在玩Scala,当使用解析器组合器时,我遇到了一些扩展它们的问题。基本上,我想要做的就是这样的事情。在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) 
    } 
} 

在这里,我想打电话给FooBarLanguageParserstatement方法BazStatement,但上面的代码,我递归调用BazStatement的方法,所以没办法将正常工作。

我已经看了一下周围的答案,我知道我可以扩展类并使用抽象覆盖,或者像这样的一些思考,但我认为这不会有什么意义,因为BazStatement是真的有一个额外的功能,我想混入我的基本解析器。我绝对不希望有一些随机的东西,如

object StrangeInheritance extends BazStatement 

授权的代码。

在Scala中会不会有任何习惯的方式来正确地做到这一点,还是我需要再次考虑应用程序的一般设计?

回答

0

使用super调用超类型的方法,也使用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) 
    } 
} 
+0

对不起,对于迟到的答案。关于这个代码的事情是'对象FooBar扩展BazStatement'完全可以工作,我可以使用'FooBarLanguageParser'中的所有方法,因为我想'BazStatement'是一个额外的功能我的'FooBarLanguageParser'。 –

+0

实际上mixin(traits)是非常惯用的scala方式,提供了特别的模块性。我认为这是默认选项,如果你想提供一种方法来将一组谨慎的行为组合成一个运行时对象。你可能是对的,确实mixin可能无法在这里工作,因为很难以可扩展的方式设计你的顶级解析器。也许在一些实用特征中有一组通用规则,然后在这个“通用规则”特征的帮助下构建“具体”底层解析器,然后尝试使用继承是更好的选择。 – vitalii

+0

感谢您的回答。我想我会像你说的那样用顶级特质定义一般规则和一些具体实现。 –