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
.
最佳答案
如果您只想使用 Scala 标准库,请查看 Numeric[T]
.在您的情况下,由于您想要进行非整数除法,因此您必须使用 Fractional[T]
Numeric
的子类.
以下是使用 scala 标准库类型类的代码的外观。请注意 Fractional
延伸自 Ordered
.在这种情况下这很方便,但它在数学上也不是通用的。例如。你不能定义 Fractional[T]
为 Complex
因为它没有订购。
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 类型类也是专门的,因此通常与直接使用原语一样快。
以下是使用 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
}
}
Spire 甚至提供从整数到
T
的自动转换如果存在 Field[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解释基本方法和一些问题。
关于scala - 如何在scala中将函数定义为所有数字的通用函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33076759/