我是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;字段。
注意:我不想偏离本文提出的方法。请仅提供有关如何修复代码的解决方案(上文),而不会大幅偏离此解决方案。
答案 0 :(得分:1)
当Scala比现在更具实验性时,这份报告可能已经超过10年了。自那以后Scala在很多地方发生了变化。但是你仍然可以通过一些修改来完成这项工作。要解决的最重要的事情是从类的多重继承。我不确定它在diamond case中的Scala是如何工作的(这正是这里发生的事情)。假设此代码有效,看起来继承必须是"virtual",即只有一组字段从公共基类继承。您仍然可以使用多个特征mixins和self 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
等不同级别上具有多重继承的类被拆分为:
Base.Num
)。这些类通常是类似于BaseNum
Behavior
特征(例如Show.NumBehavior
)在包含所有逻辑的每个级别上都可以进一步继承(aka mixins)Show.Num
)。 这种分割允许通过仅继承一个基类来创建具体类,并且#34;增强&#34;它具有Behavior
特征,是父母所有Behavior
特征的连接。