2016-02-11 14 views
1

我有以下功能,其產生2個邊界之間的均勻分佈的值:在分數[T]的方法使用雙值

def Uniform(x: Bounded[Double], n: Int): Bounded[Double] = { 
    val y: Double = (x.upper - x.lower) * scala.util.Random.nextDouble() + x.lower 
    Bounded(y, x.bounds) 
} 

和有界的定義如下:

trait Bounded[T] { 
    val underlying: T 
    val bounds: (T, T) 

    def lower: T = bounds._1 
    def upper: T = bounds._2 

    override def toString = underlying.toString + " <- [" + lower.toString + "," + upper.toString + "]" 
} 

object Bounded { 
    def apply[T : Numeric](x: T, _bounds: (T, T)): Bounded[T] = new Bounded[T] { 
    override val underlying: T = x 
    override val bounds: (T, T) = _bounds 
    } 
} 

然而,我想Uniform工作在所有的Fractional[T]值,所以我想添加一個上下文綁定:

def Uniform[T : Fractional](x: Bounded[T], n: Int): Bounded[T] = { 
    import Numeric.Implicits._ 
    val y: T = (x.upper - x.lower) * scala.util.Random.nextDouble().asInstanceOf[T] + x.lower 
    Bounded(y, x.bounds) 
} 

這樣做會在執行Uniform[Double](x: Bounded[Double])時膨脹,但其他方法不可能,並且在運行時得到ClassCastException,因爲它們不能被轉換。有沒有辦法解決這個問題?

+0

你期望有多少種不同類型的「T」?如果這是一個有限的集合,你可以考慮做一個'nextRandom [T]'函數。這隻有在你知道什麼樣的'T'期望時纔有效。 –

回答

3

我建議定義爲特徵類型,你可以得到隨機的情況下,一種新型的類:

import scala.util.Random 

trait GetRandom[A] { 
    def next(): A 
} 

object GetRandom { 
    def instance[A](a: => A): GetRandom[A] = new GetRandom[A] { 
    def next(): A = a 
    } 

    implicit val doubleRandom: GetRandom[Double] = instance(Random.nextDouble()) 
    implicit val floatRandom: GetRandom[Float] = instance(Random.nextFloat()) 
    // Define any other instances here  
} 

現在你可以寫Uniform這樣的:

def Uniform[T: Fractional: GetRandom](x: Bounded[T], n: Int): Bounded[T] = { 
    import Numeric.Implicits._ 
    val y: T = (x.upper - x.lower) * implicitly[GetRandom[T]].next() + x.lower 
    Bounded(y, x.bounds) 
} 

而且使用它像這個:

scala> Uniform[Double](Bounded(2, (0, 4)), 1) 
res15: Bounded[Double] = 1.5325899033654382 <- [0.0,4.0] 

scala> Uniform[Float](Bounded(2, (0, 4)), 1) 
res16: Bounded[Float] = 0.06786823 <- [0.0,4.0] 

有像rng這樣的庫那pr爲你提供類似的類,但他們傾向於專注於純粹的功能性方式來處理隨機數,所以如果你想要簡單一些,你可能最好是寫自己的。

+1

非常好,優雅的答案!謝謝。我今天又學到了一些東西:-) – avanwieringen

+0

我有一個問題,但是:爲什麼你使用通過名稱(=>)的函數?你也可以使它成爲'a:A'並傳遞如下的函數:'instance(Random.nextDouble)'。那是對的嗎? – avanwieringen

+0

@avanwieringen如果你使它成爲'a:A',你不會得到一個零值函數,你會得到通過應用該函數得到的值。如果你確實需要'A'的不同值,'=> A'是必須的。 :) –