2015-10-12 6 views
5

I thoughtすべてのOrdering[_]タイプにわたって私の機能をパラメータ設定する必要がありました。しかし、それは動作しません。関数をスカラーのすべての数値にわたって汎用として定義するにはどうすればよいですか?

必要な数学演算をサポートするすべてのタイプに対して、次の関数を動作させるにはどうしたらよいですか?

/** 
    * Given a list of positive values and a candidate value, round the candidate value 
    * to the nearest value in the list of buckets. 
    * 
    * @param buckets 
    * @param candidate 
    * @return 
    */ 
    def bucketise(buckets: Seq[Int], candidate: Int): Int = { 

    // x <= y 
    buckets.foldLeft(buckets.head) { (x, y) => 
     val midPoint = (x + y)/2f 

     if (candidate < midPoint) x else y 
    } 
    } 

私はIntelliJので算術演算子(/+)をクリックし、コマンドを試してみましたが、ちょうど予告Sc synthetic functionを得ました。

答えて

9

スカラ標準ライブラリのみを使用する場合は、Numeric[T]をご覧ください。あなたの場合、非整数除算を行うため、NumericのサブクラスFractional[T]を使用する必要があります。

スカラー標準ライブラリの型式を使用してコードを表示する方法を示します。 FractionalOrderedから続きます。この場合は便利ですが、数学的には一般的ではありません。例えば。注文されていないためComplexFractional[T]を定義することはできません。

def bucketiseScala[T: Fractional](buckets: Seq[T], candidate: T): T = { 
    // so we can use integral operators such as + and/
    import Fractional.Implicits._ 
    // so we can use ordering operators such as <. We do have a Ordering[T] 
    // typeclass instance because Fractional extends Ordered 
    import Ordering.Implicits._ 
    // integral does not provide a simple way to create an integral from an 
    // integer, so this ugly hack 
    val two = (implicitly[Fractional[T]].one + implicitly[Fractional[T]].one) 
    buckets.foldLeft(buckets.head) { (x, y) => 
    val midPoint = (x + y)/two 
    if (candidate < midPoint) x else y 
    } 
} 

しかし、深刻な一般的な数値計算のために私はspire見てみることをお勧め。はるかに精巧な数値型の階層構造を提供します。 Spireのタイプメーターも特殊化されているため、プリミティブを直接使用するほど高速に動作します。ここで

は尖塔を使用して見えるの例を使用する方法である:

// imports all operator syntax as well as standard typeclass instances 
import spire.implicits._ 
// we need to provide Order explicitly, since not all fields have an order. 
// E.g. you can define a Field[Complex] even though complex numbers do not 
// have an order. 
def bucketiseSpire[T: Field: Order](buckets: Seq[T], candidate: T): T = { 
    // spire provides a way to get the typeclass instance using the type 
    // (standard practice in all libraries that use typeclasses extensively) 
    // the line below is equivalent to implicitly[Field[T]].fromInt(2) 
    // it also provides a simple way to convert from an integer 
    // operators are all enabled using the spire.implicits._ import 
    val two = Field[T].fromInt(2) 
    buckets.foldLeft(buckets.head) { (x, y) => 
    val midPoint = (x + y)/two 
    if (candidate < midPoint) x else y 
    } 
} 

Field[T]が存在する場合スパイアもTの整数から自動変換を提供しますので、あなたもほぼ同じ(このように例を書くことができます非ジェネリック版)。しかし、私は上記の例が理解しやすいと思う。

// this is how it would look when using all advanced features of spire 
def bucketiseSpireShort[T: Field: Order](buckets: Seq[T], candidate: T): T = { 
    buckets.foldLeft(buckets.head) { (x, y) => 
    val midPoint = (x + y)/2 
    if (candidate < midPoint) x else y 
    } 
} 

更新:spireは非常に強力で一般的ですが、やや初心者に混乱することもあります。特に物事がうまくいかないとき。基本的なアプローチといくつかの問題を説明するexcellent blog postがあります。

+0

ありがとう、私は尖塔をチェックします。 Int(http://www.scala-lang.org/api/current/index.html#scala.Int)のscalaドキュメントが拡張された特性をリストしていないので、 'Ordering '。 'Int'がどのような特徴を持ち、数値型のものが見つかったのか、どうすればわかりますか? – jbrown

+0

@jbrown注文は[typeclass]です(http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html)。タイプメーターは継承を使用して動作しません。 –

+0

どのように知っていたのですか? – jbrown