2012-09-23 60 views
1

如何在Scala中聲明實現多個算術系統所需的類型簽名,這些算法系統共享一個聲明操作的相同特徵?我想我已經解決了,直到我嘗試添加一些輔助實現到基礎特徵/類。在下面的代碼片段(編譯)中注意到sq()被定義爲這個* self而不是這個更明顯。並且self()不能在特徵中實現(我們必須等到我們到達具體的擴展類來實現它)。如何在Scala中聲明類型參數化算術?

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) } 
} 

問題/目標是:刪除使用自()或(至少移動自()的實現到NumberBase)不改變*類型簽名D.很多修復中上面的鏈接使得派生類不可實現(類似於新D()不是可由*或*在D中具有不可猜出類型簽名的類型可返回的類型)。我不介意一些簽名變得醜陋 - 但我希望代碼能夠表達這些代碼表達的內容:派生類僅在它們自己的類型上工作並返回它們自己類型的實例(它們不會上下移動在一個層次結構中)。

我在這裏發現了一些討論,列出了一些問題(但沒有看到解決方案):http://www.scala-lang.org/node/839。直到看到基類和實現時纔會遇到一些問題。

上面給出的解決方法(迫使實現類實現self())的完整代碼如下所示:https://github.com/WinVector/AutoDiff其中我們使用不同的算術系統共享相同的基類或特徵來編寫泛型函數通過不同的算術實現。這讓我們可以使用標準機器算術(比如D)或其他東西(比如計算梯度作爲副作用的數字系統)。

+0

這也是相關的:https://tpolecat.github.io/2015/04/29/f-bounds.html – Daenyth

回答

3

我想你想使用自類型,這將確保NumberBase[N]實例將N類型的實例:

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) 

但是,如果你真的要定義一個新的數字類型,你應該做Scala圖書館自己做的事情,並且使用類型類別Numeric

+0

非常感謝。這不僅解決了我的玩具示例,而且它也是更大代碼中的問題。 – jmount