如何在Scala中声明实现多个算术系统所需的类型签名,这些算法系统共享相同的特征来声明操作?我以为我已经解决了,直到我尝试将一些辅助实现添加到基本特征/类。在下面的代码片段(编译)中注意到sq()被定义为this * self而不是更明显的* this。并且self()也不能在特征中实现(我们必须等到我们到达具体的扩展类来实现它)。
trait NumberBase [NUMBERTYPE <: NumberBase[NUMBERTYPE]] {
// type NUMBERTYPE >: this.type
def *(that: NUMBERTYPE):NUMBERTYPE
def self:NUMBERTYPE
def sq:NUMBERTYPE = { this*self }
}
class D(val v:Double) extends NumberBase[D] {
def self:D = { this }
def *(that: D):D = { new D(this.v*that.v) }
}
问题/目标是:删除使用self()或(至少将self()的实现移动到NumberBase中)而不更改D中*的类型签名。上面的链接使得派生类不可实现(像新的D()这样的东西不是*或*可返回的类型,在D中有一个不可思议的类型签名)。我不介意一些签名变得更加丑陋 - 但我希望代码能够表达这段代码表达的内容:派生类只能处理它们自己的类型并返回它们自己类型的实例(它们不会向上移动)在层次结构中。)
我在这里找到了一些讨论,列出了一些问题(但没有看到解决方案):http://www.scala-lang.org/node/839。在您看到基类和实现之前,您不会遇到一些问题。
这里给出了上面给出的解决方法的完整代码(强制实现类来实现self()):https://github.com/WinVector/AutoDiff我们使用不同的算术系统共享相同的基类或特性来编写函数对于不同的算术实现是通用的。这让我们可以使用标准机器算法(如D)或其他东西(比如计算渐变作为副作用的数字系统)。
答案 0 :(得分:3)
我认为您希望使用自我类型,这将确保NumberBase[N]
实例 也是<{1}}类型的实例:
N
但是,如果你真的想要定义一种新类型的数字,你应该做Scala库本身所做的事情并使用trait NumberBase[N <: NumberBase[N]] { this: N =>
def *(that: N): N
def sq: N = this * this
}
class D(val v: Double) extends NumberBase[D] {
def *(that: D): D = new D(this.v * that.v)
}
val a = new D(0.5)
val b = new D(0.25)
a * b // D(0.125)
a.sq // D(0.25)
类型类。