在 Fractional[T] 方法中使用双精度值

Using a double value in a Fractional[T] method

我有以下函数生成 2 个边界之间的均匀分布值:

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)
}

和Bounded定义如下:

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,因为它们不能被转换。有办法解决吗?

我建议定义一个新类型 class 来表征您可以获得以下随机实例的类型:

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 这样的库为您提供了类似的类型 class,但它们往往专注于处理随机数的纯函数式方法,所以如果您想要更简单的东西,您最好自己写一个。