2012-05-13 18 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]を。

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をコピーする醜い定型だ:バイナリ組合交差点演算子を追加するには、私はコンパニオンオブジェクトで(implicit num: Numeric[T])と同様のパターンに従いました。 Intervalオブジェクト自体のレベルでこれを何度もやる方法がありますか? IntervalオブジェクトでNumeric型クラスの

答えて

8

はいあります。

最初にインポートします。代わりに、Intervalの範囲でOrdering.Implicits._をインポートできます。これらの暗黙で

object Interval { 
    import Ordering.Implicits._ 

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

それは発注作業を見つけたとき、それは操作が起こる範囲に(数字は注文です)暗黙の注文を探します。そして、それぞれのルーチンにスコープ内に暗黙のうちに1つの適切なものが存在することになります。算術演算も必要な場合は、Numeric.Implicits._

を暗黙の引数でインポートします。バインドコンテキストと呼ばれるそのための言語での近道は、あります: あなたがdef f[T: X](args)はなくdef f[T](args)(implicit someName: X[T])

を書くことができるの違いは、あなたがすることができます(バインドコンテキストで暗黙的に名前を持っていないということですまた、compainonオブジェクト `Interval`がいいです幸いにも、あなたがそうインポートをもう名前が必要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

用途は、その外側の範囲のどこかにバインドしなければならないタイプのパラメータTを持っています。固有の定数値であるIntervalはそのバインディングを提供できません。この特定の問題に

一つの解決策は、彼らがTの結合と関連したNumericインスタンスを共有することになり、その場合には通常のインスタンスメソッドとしてIntervalクラス、にあなたのunionintersect操作の定義を移動するだろう

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クラス、1つのアプローチから、あなたがthroug追いかける必要がある暗黙の決まり文句の量を減少させることに、クラスの残りの部分、あなたのAPIはNumeric [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) 
} 

第三のオプションは、追加の方法で元のクラスを豊かにする暗黙的な定義を使用して、これら2つ、

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] 
を組み合わせ、のような使用になり、例えば、

// 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 : Ops[T]) = { 
    val i3 = i1 union i2 
    val i4 = i1 intersect i2 
    (i3, i4) 
} 
+0

。implictly [T]を使用しますが、これはほとんど短いです暗黙的な変換を行う場所。次に、 'use'メソッドの最後の例では、プロ'数値:Numeric'コンテキスト境界を使用してください。 – 4e6

+0

ありがとうございます。私の工場のための多くの手袋! –