Scala 中的通用点加法

Generic Point Addition in Scala

我正在尝试使用加法和 Scala 乘法成员来调整 Tuple(2) class,这样我就可以更轻松地将它们用作几何二维点。这就是我得到的:

implicit class Point[+T: Numeric](val t: (T, T)) {
  import Numeric.Implicits._
  def _1 = t._1
  def _2 = t._2

  def +[V >: T](p: Point[V])(implicit ev: Numeric[V]) : (V,V) = 
    (ev.plus(t._1, p._1), ev.plus(t._2, p._2))
}

println((2, 3) + Point(5.0, 6.0))

这不起作用(找不到 ev)大概是因为严格来说 Float 不是 Int 的超类型 - 但实际上似乎没有是一个弱一致性约束运算符,完全将其排除在外意味着我不能再使用 ev.plus 因为它需要两个相同类型的值 V,而不是 TV 之一。

如何正确实施此代码?

你完全正确。问题是 Numeric[T] 不允许根据其签名混合类型(VT):def plus(x: T, y: T): T.

您可以 use/emulate 这个库: https://github.com/azavea/numeric。它做了很多隐式体操以允许混合类型工作。

它完全满足您的需求:

EasyImplicits allows you to operate on mixed numeric types (e.g. T + U + Int).

或者选择使用基础 Double 类型而不是 T/V - 我知道这并不总是很好(精度损失等)。

您的代码仍然适用于不混合类型的点,这还不错,否则 Double 看起来并不那么糟糕,因为无论如何都会发生自动转换。

我认为因为构造函数参数是一个元组,所以它使本应简单的数字扩展变得复杂。这涵盖了许多(大多数?)转化。

implicit class Point[T: Numeric](a: (T, T)) {
  import Numeric.Implicits._
  val _1 = a._1
  val _2 = a._2

  def +(x: T, y: T) = add(_1, _2, x, y)

  def +[U: Numeric](x:U, y:U)(implicit ev: T => U) =
    add[U](ev(_1), ev(_2), x, y)

  def +[U: Numeric](b: Point[U])(implicit ev: T => U) =
    add[U](ev(_1), ev(_2), b._1, b._2)

  private def add[N: Numeric](a:N, b:N, c:N, d:N) = (a+c, b+d)
}

用法:

(1, 4) + (2.2, 4.4)         //res0: (Double, Double) = (3.2,8.4)
(2.1, 3.1) + (9, 2)         //res1: (Double, Double) = (11.1,5.1)
(1, 4) + Point((5.2, 6.2))  //res2: (Double, Double) = (6.2,10.2)
Point((2, 3)) + (4L, 5L)    //res3: (Long, Long) = (6,8)
Point((1.5, 2.9)) + (1, 1)  //res4: (Double, Double) = (2.5,3.9)

但它不会加宽作为参数传递给 +() 方法的现有 Point 的元素。

(3.3, 4.5) + Point((1, 3))  //Error:No implicit view available from Double => Int.