Scala 覆盖可堆叠特征模式中的抽象类型成员

Scala 覆盖可堆叠特征模式中的抽象类型成员,scala,traits,abstract-type,Scala,Traits,Abstract Type,假设我们想要定义如何在某些数据上累积结果的方法: case class Data(x: Int, y: Int) 我们定义了这样做的特征: trait Accumulator { type R def add(acc: R, d: Data): R def zero: R } 以及一个简单的实现: trait XAccumulator extends Accumulator { type R = Int def add(acc: Int, d: Data) = ac

假设我们想要定义如何在某些数据上累积结果的方法:

case class Data(x: Int, y: Int)
我们定义了这样做的特征:

trait Accumulator {
  type R   
  def add(acc: R, d: Data): R
  def zero: R
}
以及一个简单的实现:

trait XAccumulator extends Accumulator {
  type R = Int
  def add(acc: Int, d: Data) = acc + d.x
  def zero = 0
}
我想使用stackable trait模式来使用这些简单累加器中的多个:

trait TraceYAccumulator extends Accumulator {
  abstract override type R = (Seq[Int], super.R)
  // fails:
  // `abstract override' modifier not allowed for type members

  def add(acc: R, d: Data) = {
    val r = super.add(acc._2, d)
    (acc._1 :+ d.y, r)
  }

  def zero = (Seq.empty[Int], super.zero)
}
显然,我不允许重写抽象类型成员。如何使用stackable trait模式更改被重写方法的结果类型

我的第二种方法是使用类型参数:

trait Accumulator[R] {
  def add(acc: R, d: Data): R
  def zero: R
}

trait XAccumulator extends Accumulator[Int] {
  def add(acc: Int, d: Data) = acc + d.x
  def zero = 0
}
但现在它变得非常奇怪:

trait TraceYAccumulator[T] extends Accumulator[(Seq[Int], T)] {
  this: Accumulator[T] =>

  def add(acc: (Seq[Int], T), d: Data): (Seq[Int], T) = {
    val r = this.add(acc._2, d)
    // fails: overloaded method value add with alternatives:
    // (acc: (Seq[Int], T),d: Data)(Seq[Int], T) <and>
    // (acc: _14695,d: Data)_14695 cannot be applied to (T, Data)
    (acc._1 :+ d.y, r)
  }
  def zero: (Seq[Int], T) = (Seq.empty[Int], this.zero)
}
trait tracey累加器[T]扩展累加器[(Seq[Int],T)]{
此:累加器[T]=>
def add(附件:(序号[Int],T),d:数据):(序号[Int],T)={
val r=此添加(根据2,d)
//失败:重载方法值添加选项:
//(附件:(序号[Int],T),d:数据)(序号[Int],T)
//(acc:_14695,d:数据)_14695不能应用于(T,数据)
(附件1:+d.y,r)
}
定义零:(Seq[Int],T)=(Seq.empty[Int],this.zero)
}
由于超类和混合类具有相同的方法名(显然),我们无法引用正确的方法。我唯一的选择是使用构图吗


如何堆叠此类操作?

第一种方法有一个基本的理论问题:

假设我们被允许写这些特征。然后考虑以下内容:

val acc = new XAccumulator with TraceYAccumulator
val xacc = acc: XAccumulator
由于
xacc
是一个
xaccumpulator
,我们知道
x.R=:=Int
。哎呀

第二种方法有一个实现问题:不能从同一特性的不同实例继承

illegal inheritance; anonymous class $anon inherits different type instances of trait Accumulator: Accumulator[Int] and Accumulator[(Seq[Int], Int)]

因此,组合(或者某些类型类黑客)似乎是唯一的选择。

不确定这是否会像您希望的那样起作用。stackable trait模式涉及通过调用super将函数彼此链接起来。如果链中的每个特征都可能具有不同的泛型类型,那么我看不出调用如何正确地进行链。如果它们都是用相同的类型参数化的,这可能会起作用。@cmbaxter调用可以正确地链接,因为堆叠特性将堆叠特性的返回类型作为其返回类型。当然,整个堆栈的最终返回类型将取决于堆栈特征的顺序。我看不出我的方法的理论问题在哪里。