scala中的表达式问题解决方案

时间:2017-12-13 02:35:29

标签: scala

我是Scala的新手。考虑一下这篇文章(http://scala-lang.org/docu/files/IC_TECH_REPORT_200433.pdf)。本文介绍了Scala中表达式问题(https://en.wikipedia.org/wiki/Expression_problem)的两种解决方案。在第3节中,它提出了面向对象的解决方案,在第4节中,它提出了一种功能方法。

我正在尝试从第3节中的解决方案构建一个完整的程序。因此,我在下面的代码作为我的scala程序(文件名:' ep.scala')。

trait Base {
  type exp <: Exp;
  trait Exp {
    def eval: Int
  }
  class Num(v: Int) extends Exp {
    val value = v;
    def eval = value
  }
}

trait BasePlus extends Base {
  class Plus(l: exp, r: exp) extends Exp {
    val left = l; val right = r;
    def eval = left.eval + right.eval
  }
}

trait BaseNeg extends Base {
  class Neg(t: exp) extends Exp {
    val term = t;
    def eval = - term.eval;
  }
}

trait BasePlusNeg extends BasePlus with BaseNeg;

trait Show extends Base {
  type exp <: Exp;
  trait Exp extends super.Exp {
    def show: String;
  }
  class Num(v: Int) extends super.Num(v) with Exp {
    def show = value.toString();
  }
}

trait ShowPlusNeg extends BasePlusNeg with Show {
  class Plus(l: exp, r: exp) extends super.Plus(l, r) with Exp {
    def show = left.show + "+" + right.show;
  }
  class Neg(t: exp) extends super.Neg(t) with Exp {
    def show = "-(" + term.show + ")";
  }
}

trait DblePlusNeg extends BasePlusNeg {
  type exp <: Exp;
  trait Exp extends super.Exp {
    def dble: exp;
  }
  def Num(v: Int): exp;
  def Plus(l: exp, r: exp): exp;
  def Neg(t: exp): exp;
  class Num(v: Int) extends super.Num(v) with Exp {
    def dble = Num(v * 2);
  }
  class Plus(l: exp, r: exp) extends super.Plus(l, r) with Exp {
    def dble = Plus(left.dble, right.dble);
  }
  class Neg(t: exp) extends super.Neg(t) with Exp {
    def dble = Neg(t.dble);
  }
}

trait ShowDblePlusNeg extends ShowPlusNeg with DblePlusNeg {
  type exp <: Exp;
  trait Exp extends super[ShowPlusNeg].Exp 
           with super[DblePlusNeg].Exp;
  class Num(v: Int) 
    extends super[ShowPlusNeg].Num(v)
       with super[DblePlusNeg].Num(v)
       with Exp;
  class Plus(l: exp, r: exp)
    extends super[ShowPlusNeg].Plus(l, r)
       with super[DblePlusNeg].Plus(l, r)
       with Exp;
  class Neg(t: exp)
    extends super[ShowPlusNeg].Neg(t)
       with super[DblePlusNeg].Neg(t)
       with Exp;
}

trait Equals extends Base {
  type exp <: Exp;
  trait Exp extends super.Exp {
    def eql(other: exp): Boolean;
    def isNum(v: Int) = false;
  }
  class Num(v: Int) extends super.Num(v) with Exp {
    def eql(other: exp): Boolean = other.isNum(v);
    override def isNum(v: Int) = v == value;
  }
}

trait EqualsPlusNeg extends BasePlusNeg with Equals {
  type exp <: Exp;
  trait Exp extends super[BasePlusNeg].Exp
           with super[Equals].Exp {
    def isPlus(l: exp, r: exp): Boolean = false;
    def isNeg(t: exp): Boolean = false;
  }
  class Num(v: Int) extends super[Equals].Num(v)
                   with Exp;
  class Plus(l: exp, r: exp) extends Exp
                            with super.Plus(l, r) {
    def eql(other: exp): Boolean = other.isPlus(l, r);
    override def isPlus(l: exp, r: exp) = (left eql l) && (right eql r)
  }
  class Neg(t: exp) extends Exp
                   with super.Neg(t) {
    def eql(other: exp): Boolean = other.isNeg(t);
    override def isNeg(t: exp) = term eql t
  }
}

trait EqualsShowPlusNeg extends EqualsPlusNeg
                       with ShowPlusNeg {
  type exp <: Exp;
  trait Exp extends super[EqualsPlusNeg].Exp
           with super[ShowPlusNeg].Exp;
  class Num(v: Int)
    extends super[EqualsPlusNeg].Num(v)
       with super[ShowPlusNeg].Num(v)
       with Exp;
  class Plus(l: exp, r: exp)
    extends super[EqualsPlusNeg].Plus(l, r)
       with super[ShowPlusNeg].Plus(l, r)
       with Exp;
  class Neg(term: exp)
    extends super[EqualsPlusNeg].Neg(term)
       with super[ShowPlusNeg].Neg(term)
       with Exp;
}

但是当我尝试使用scalac ep.scala编译它时,我收到以下错误:

ep.scala:72: error: class Num needs to be a trait to be mixed in
       with super[DblePlusNeg].Num(v)
                           ^
ep.scala:76: error: class Plus needs to be a trait to be mixed in
       with super[DblePlusNeg].Plus(l, r)
                           ^
ep.scala:80: error: class Neg needs to be a trait to be mixed in
       with super[DblePlusNeg].Neg(t)
                           ^
ep.scala:106: error: class Plus needs to be a trait to be mixed in
                            with super.Plus(l, r) {
                                       ^
ep.scala:111: error: class Neg needs to be a trait to be mixed in
                   with super.Neg(t) {
                              ^
ep.scala:124: error: class Num needs to be a trait to be mixed in
       with super[ShowPlusNeg].Num(v)
                           ^
ep.scala:128: error: class Plus needs to be a trait to be mixed in
       with super[ShowPlusNeg].Plus(l, r)
                           ^
ep.scala:132: error: class Neg needs to be a trait to be mixed in
       with super[ShowPlusNeg].Neg(term)
                           ^
8 errors found

请解释如何解决这些错误。

我正在使用scala版本2.11.8。根据我的理解,scala中的retrocompatibilty有一些中断,从当前版本w.r.t.文章的版本。我已经调整了代码来修复因这些语言差异引起的小问题,但是这8个错误(都是同一类型的)仍然存在。 试图将错误指示的类声明为特征 没有帮助,因为特征不能有参数&#34; as&#34;字段。

注意:我不想偏离本文提出的方法。请仅提供有关如何修复代码的解决方案(上文),而不会大幅偏离此解决方案。

1 个答案:

答案 0 :(得分:1)

当Scala比现在更具实验性时,这份报告可能已经超过10年了。自那以后Scala在很多地方发生了变化。但是你仍然可以通过一些修改来完成这项工作。要解决的最重要的事情是从类的多重继承。我不确定它在diamond case中的Scala是如何工作的(这正是这里发生的事情)。假设此代码有效,看起来继承必须是"virtual",即只有一组字段从公共基类继承。您仍然可以使用多个特征mixinsself types的继承来在Scala中模拟这个。您可以尝试这样做:

trait Base {
  type exp <: Exp

  trait Exp {
    def eval: Int
  }


  class Num(val value: Int) extends Exp {
    def eval: Int = value
  }

  type BaseNum = Num
}

trait BasePlus extends Base {

  class Plus(val left: exp, val right: exp) extends Exp {
    def eval: Int = left.eval + right.eval
  }

  type BasePlus = Plus
}

trait BaseNeg extends Base {

  class Neg(val term: exp) extends Exp {
    def eval = -term.eval
  }

  type BaseNeg = Neg
}

trait BasePlusNeg extends BasePlus with BaseNeg

trait Show extends Base {
  type exp <: Exp

  trait Exp extends super.Exp {
    def show: String
  }

  trait NumBehavior extends Exp {
    self: BaseNum =>
    override def show: String = value.toString
  }

  final class Num(v: Int) extends BaseNum(v) with NumBehavior with Exp

}

trait ShowPlusNeg extends BasePlusNeg with Show {

  trait PlusBehavior {
    self: BasePlus =>
    def show = left.show + "+" + right.show;
  }

  final class Plus(l: exp, r: exp) extends BasePlus(l, r) with PlusBehavior with Exp

  trait NegBehavior {
    self: BaseNeg =>
    def show = "-(" + term.show + ")";
  }

  class Neg(t: exp) extends BaseNeg(t) with NegBehavior with Exp

}

trait DblePlusNeg extends BasePlusNeg {
  type exp <: Exp

  trait Exp extends super.Exp {
    def dble: exp
  }

  def Num(v: Int): exp

  def Plus(l: exp, r: exp): exp

  def Neg(t: exp): exp


  trait NumBehavior {
    self: BaseNum =>
    def dble = Num(value * 2)
  }

  final class Num(v: Int) extends BaseNum(v) with NumBehavior with Exp


  trait PlusBehavior {
    self: BasePlus =>
    def dble = Plus(left.dble, right.dble)
  }

  class Plus(l: exp, r: exp) extends BasePlus(l, r) with PlusBehavior with Exp


  trait NegBehavior {
    self: BaseNeg =>
    def dble = Neg(term.dble)
  }

  class Neg(t: exp) extends super.Neg(t) with NegBehavior with Exp

}

trait ShowDblePlusNeg extends ShowPlusNeg with DblePlusNeg {
  type exp <: Exp

  trait Exp extends super[ShowPlusNeg].Exp with super[DblePlusNeg].Exp;

  trait NumBehavior extends super[ShowPlusNeg].NumBehavior with super[DblePlusNeg].NumBehavior {
    self: BaseNum =>
  }

  final class Num(v: Int) extends BaseNum(v)
    with NumBehavior
    with Exp


  trait PlusBehavior extends super[ShowPlusNeg].PlusBehavior with super[DblePlusNeg].PlusBehavior {
    self: BasePlus =>
  }

  final class Plus(l: exp, r: exp) extends BasePlus(l, r)
    with PlusBehavior
    with Exp

  trait NegBehavior extends super[ShowPlusNeg].NegBehavior with super[DblePlusNeg].NegBehavior {
    self: BaseNeg =>
  }

  final class Neg(t: exp) extends BaseNeg(t)
    with NegBehavior
    with Exp

}

trait Equals extends Base {
  type exp <: Exp;

  trait Exp extends super.Exp {
    def eql(other: exp): Boolean;

    def isNum(v: Int): Boolean = false;
  }

  trait NumBehavior extends Exp {
    self: BaseNum =>
    def eql(other: exp): Boolean = other.isNum(value);

    override def isNum(v: Int) = v == value;
  }


  final class Num(v: Int) extends BaseNum(v) with NumBehavior with Exp

}

trait EqualsPlusNeg extends BasePlusNeg with Equals {
  type exp <: Exp;

  trait Exp extends super[BasePlusNeg].Exp
    with super[Equals].Exp {
    def isPlus(l: exp, r: exp): Boolean = false;

    def isNeg(t: exp): Boolean = false;
  }


  final class Num(v: Int) extends BaseNum(v)
    with NumBehavior // effectively super[Equals].NumBehavior
    with Exp


  trait PlusBehavior extends Exp {
    self: BasePlus =>
    def eql(other: exp): Boolean = other.isPlus(left, right);

    override def isPlus(l: exp, r: exp) = (left eql l) && (right eql r)
  }

  final class Plus(l: exp, r: exp) extends BasePlus(l, r) with PlusBehavior with Exp


  trait NegBehavior extends Exp {
    self: BaseNeg =>
    def eql(other: exp): Boolean = other.isNeg(term);

    override def isNeg(t: exp) = term eql t
  }

  final class Neg(t: exp) extends BaseNeg(t) with NegBehavior with Exp

}

trait EqualsShowPlusNeg extends EqualsPlusNeg with ShowPlusNeg {
  type exp <: Exp

  trait Exp extends super[EqualsPlusNeg].Exp
    with super[ShowPlusNeg].Exp


  trait NumBehavior extends super[EqualsPlusNeg].NumBehavior with super[ShowPlusNeg].NumBehavior {
    self: BaseNum =>
  }

  class Num(v: Int) extends BaseNum(v) with NumBehavior with Exp

  trait PlusBehavior extends super[EqualsPlusNeg].PlusBehavior with super[ShowPlusNeg].PlusBehavior {
    self: BasePlus =>
  }

  class Plus(l: exp, r: exp) extends BasePlus(l, r) with PlusBehavior with Exp

  trait NegBehavior extends super[EqualsPlusNeg].NegBehavior with super[ShowPlusNeg].NegBehavior {
    self: BaseNeg =>
  }

  class Neg(term: exp) extends BaseNeg(term) with NegBehavior with Exp

}

最后,您可以创建一些组合特征的实例,例如

object EqualsShowPlusNegInstance extends EqualsShowPlusNeg {
  override type exp = Exp
}

object ShowDblePlusNegInstance extends ShowDblePlusNeg {
  override type exp = Exp

  override def Num(v: Int) = new Num(v)

  override def Plus(l: Exp, r: Exp) = new Plus(l, r)

  override def Neg(t: Exp) = new Neg(t)
}

然后你可以这样做:

def test1() = {
  import EqualsShowPlusNegInstance._
  println("EqualsShowPlusNegInstance:")
  println(new Num(3).show)
  // println(new Num(3).dble.show) // compilation error for dble
  println(new Plus(new Num(3), new Num(4)).show)
  // println(new Plus(new Num(3), new Num(4)).dble.show) // compilation error for dble
  println(new Num(3).eql(new Num(4)))

}

def test2() = {
  import ShowDblePlusNegInstance._
  println("ShowDblePlusNegInstance:")
  println(new Num(3).show)
  println(new Num(3).dble.show)
  println(new Plus(new Num(3), new Num(4)).show)
  println(new Plus(new Num(3), new Num(4)).dble.show)
  // println(new Num(3).eql(new Num(4)))  // compilation error for eql
}

这里最重要的技巧是在Num等不同级别上具有多重继承的类被拆分为:

  1. 单基类(例如Base.Num)。这些类通常是类似于BaseNum
  2. 的类型
  3. Behavior特征(例如Show.NumBehavior)在包含所有逻辑的每个级别上都可以进一步继承(aka mixins
  4. 每个级别的具体最终课程(例如Show.Num)。
  5. 这种分割允许通过仅继承一个基类来创建具体类,并且#34;增强&#34;它具有Behavior特征,是父母所有Behavior特征的连接。