2011-01-26 5 views
10

Scalaには、タイプクラスとして使用できる多くの特性があります。には、OrderedNumericなどのタイプクラスがあります。NumericがOrderと異なる動作をするのはなぜですか?

私は、例えば、このような Orderedを使用してジェネリックメソッドを書くことができます

def f[T <% Ordered[T]](a: T, b: T) = if (a < b) a else b 

私はNumericと同じようなことをやってみたかったが、これは動作しません:

def g[T <% Numeric[T]](a: T, b: T) = a * b 

OrderedNumericの間に明らかな相違があるのはなぜですか?

私はこれを行うには、他の方法がある知っている、次のように動作します(バインドされたコンテキストを使用しています):

def g[T : Numeric](a: T, b: T) = implicitly[Numeric[T]].times(a, b) 

しかし、それはちょうど2つの数値を乗算する*を使用することができることよりも複雑に見えます。なぜNumericの形質に*のようなメソッドが含まれないのに対して、Orderedには<のようなメソッドが含まれていますか?私が知っている

は、またthis answerも参照あなたがNumericと同じように使用することができますOrderingがあります:

def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b) 

答えて

5

Orderedは、IntまたはBooleanのいずれかを返す単純なポンピングされたメソッドのほんの一部であり、タイプトリッキーは必要ありません。一方、使用される厳密なサブクラスに応じて異なる型を返すメソッドを持っています。したがって、Orderedはマーカー形質よりも少ししかありませんが、Numericは完全機能型クラスです。

オペレータを元に戻すには、lhsオペランドにmkNumericOpsNumericで定義)を使用できます。

UPDATE

マイルはmkNumericOpsは暗黙的である、かなり右で、これだけの数値のインスタンスをインポートすると、すべての魔法をあなたにお返しします...

12

シンボリック事業者が用意されていますが、暗黙的な数値[T]からインポートする場合

def g[T : Numeric](a: T, b: T) = { 
    val num = implicitly[Numeric[T]] 
    import num._ 
    a * b 
} 

これは単なる演算子を使用したい場合は明らかに少し難しいですが、単純なケースではインポートのオーバーヘッドがそれほど大きくないわけではありません。

なぜ演算子は明示的なインポートなしで利用できないのですか?これらの演算子が広く使用されているため、暗黙的にimplicitsをデフォルトで表示することに対する通常の考慮がここで適用されます。

5

あなただけのこれを行うことにより、1本の余分なラインを使用してマイルのソリューションを減らすことができます。その後、あなたの方法でスコープにこれを持参

Numeric[A]#Ops

object Ops { 
    implicit def numeric[A : Numeric](a: A) = implicitly[Numeric[A]].mkNumericOps(a) 
} 

A : Numericから暗黙の型変換を追加

def g[T : Numeric](a: T, b: T) = { 
    import Ops.numeric 
    a * b 
} 

詳細はScala ticket 3538を参照してください。

+0

素敵...とてもエレガント! –

関連する問題