2012-05-13 50 views
6

我有以下的一般間隔類(由用戶SOC好心制定對我來說):Scala的隱式數值[T]同伴對象

case class Interval[T](from: T, to: T)(implicit num: Numeric[T]) { 
    import num.mkNumericOps // allows us to write from.toDouble and to.toDouble 
    def mid: Double = (from.toDouble + to.toDouble)/2.0 
} 

典型使用案例:間隔[雙]或間隔[INT]。要添加二進制工會路口運營商我跟着同伴對象與(implicit num: Numeric[T])類似的模式:

object Interval { 

    def union[T](interval1: Interval[T], interval2: Interval[T])(implicit num: Numeric[T]) = { 
    import num.mkOrderingOps // allows interval1.from min 
    Interval[T](interval1.from min interval2.from, interval1.to max interval2.to) 
    } 

    def intersect[T](interval1: Interval[T], interval2: Interval[T])(implicit num: Numeric[T]) = { 
    import num.mkOrderingOps 
    Interval[T](interval1.from max interval2.from, interval1.to min interval2.to) 
    } 

} 

這是醜陋的樣板複製這兩種方法裏面(implicit num: Numeric[T])import num.mkOrderingOps。在Interval對象本身的層面上,有沒有辦法只做一次?

回答

8

是的。

先導入。您可以在Interval的範圍內導入Ordering.Implicits._。

object Interval { 
    import Ordering.Implicits._ 

    def union[T](....)(implicit num: Numeric[T]) = { 
    // do not import num.mkOrderingOps 
    ... 
    } 
    ... 
} 

有了這些implicits,當它找到一個排序操作,它會尋找隱訂購(數字爲順序)的範圍,其中的操作情況。在每個例程中恰好有一個隱含的範圍。如果您還需要算術運算,請同時導入Numeric.Implicits._

現在使用隱式參數。有一個在語言說,這就是所謂的上下文綁定的快捷方式: 你可以寫def f[T: X](args)而不是def f[T](args)(implicit someName: X[T])

不同的是,你沒有爲隱與綁定的情況下有一個名稱(可使用implictly [T],但那麼這是很難縮短。幸運的是,你不要再需要一個名字與進口Ordering.Implicits._

所以

object Interval { 
    import Ordering.Implicits._ 
    // also import Numeric.Implicits._ if you need +,-,*,/ ... 
    def union[T: Numeric] ... 
    def intersection[T: Numeric] ... 
} 
+0

謝謝。很簡潔。我從來沒有見過這種背景限制的想法。人們在哪裏學習這些東西?我讀過一本關於Scala的書,但我不記得上下文的界限。 –

+0

請參閱示例[什麼是Scala中的「上下文綁定」?](http://stackoverflow.com/questions/2982276/what-is-a-context-bound-in-scala)。 – Jesper

5

Interval對象中使用Numeric類型類的類型參數的類型參數爲T,該類型參數必須在其封閉範圍內的某處進行綁定。作爲唯一常數值的Interval不能提供該綁定。

一個解決這個特定的問題,將是您的unionintersect操作的定義移動到Interval作爲普通的實例方法,在這種情況下,他們將分享T的結合,並與相關的Numeric實例該類的其餘部分,

case class Interval[T : Numeric](from: T, to: T) { 
    import Numeric.Implicits._ 
    import Ordering.Implicits._ 

    def mid: Double = (from.toDouble + to.toDouble)/2.0 
    def union(interval2: Interval[T]) = 
    Interval(this.from min interval2.from, this.to max interval2.to) 
    def intersect(interval2: Interval[T]) = 
    Interval(this.from max interval2.from, this.to min interval2.to) 
} 

但是,如果您希望保留這些操作的定義,獨立於Interval類,辦法來減少隱性的樣板,你需要追逐通過量量你的API是用Numeric [T]來定義你自己的更高級類型類。例如,

// Type class supplying union and intersection operations for values 
// of type Interval[T] 
class IntervalOps[T : Numeric] { 
    import Ordering.Implicits._ 

    def union(interval1: Interval[T], interval2: Interval[T]) = 
    Interval[T](interval1.from min interval2.from, interval1.to max interval2.to) 

    def intersect(interval1: Interval[T], interval2: Interval[T]) = 
    Interval[T](interval1.from max interval2.from, interval1.to min interval2.to) 
} 

implicit def mkIntervalOps[T : Numeric] = new IntervalOps[T] 

,在使用時會是什麼樣子,

def use[T](i1 : Interval[T], i2 : Interval[T])(implicit ops : IntervalOps[T]) = { 
    import ops._ 
    val i3 = union(i1, i2) 
    val i4 = intersect(i1, i2) 
    (i3, i4) 
} 

第三個選項結合這兩點,使用隱含的定義,以豐富額外的方法原始類,

class IntervalOps[T : Numeric](interval1 : Interval[T]) { 
    import Ordering.Implicits._ 

    def union(interval2: Interval[T]) = 
    Interval[T](interval1.from min interval2.from, interval1.to max interval2.to) 

    def intersect(interval2: Interval[T]) = 
    Interval[T](interval1.from max interval2.from, interval1.to min interval2.to) 
} 

implicit def enrichInterval[T : Numeric](interval1 : Interval[T]) = 
    new IntervalOps[T](interval1) 

type Ops[T] = Interval[T] => IntervalOps[T] 

然後在使用中,

def use[T](i1 : Interval[T], i2 : Interval[T])(implicit ops : Ops[T]) = { 
    val i3 = i1 union i2 
    val i4 = i1 intersect i2 
    (i3, i4) 
} 
+0

此外,compainon對象'Interval'是一個很好的放置隱式轉換,然後,在最後一個使用'use'方法的例子中,你只需要pro vide'Numeric'上下文邊界'使用[T:Numeric](i1:Interval [T],i2:Interval [T])' – 4e6

+0

Thanks Miles。我的磨坊有很多的味道! –