Scala 泛型和数字隐式

发布于 2024-12-09 17:06:56 字数 1038 浏览 0 评论 0原文

我需要将两个函数作为参数传递给 scala 函数。然后,该函数应该评估它们并从中获取一个数字,然后对其进行操作。该数字可以是 Int、Double 或任何其他数字类型。我希望该函数能够工作,无论它使用什么类型。

下面的例子解释了这个问题。

import Numeric.Implicits._

class Arithmetic[T : Numeric](val A: Connector[T], val B: Connector[T]) {
  val sum  = new Connector({ A.value + B.value })
}

class Constant[T](var x: T) {
  val value = new Connector({ x })
}

class Connector[T](f: => T) {
  def value: T = f
  override def toString = value.toString()
}

object Main extends App{
  val n1 = new Constant(1)

  // works
  val n5 = new Constant(5)
  val a = new Arithmetic( n1.value, n5.value )
  println(a.sum)

 // no works
 val n55 = new Constant(5.5)
 val b = new Arithmetic( n1.value, n55.value )
 println(b.sum)

}

我也尝试

class Arithmetic[T,R : Numeric](val A: Connector[T], val B: Connector[R]) {

过其他几种组合,但最终我得到了

error: could not find implicit value for parameter num: scala.math.Numeric[Any]
val sum  = new Connector({ A.value + B.value })

I need to pass two functions as parameters to a scala function. That function should then evaluate them and get a number from them where it will then operate on. This number can be either a Int, Double or any other numeric type. I would like the function to work, whatever the types it is working with.

The example bellow explains the issue.

import Numeric.Implicits._

class Arithmetic[T : Numeric](val A: Connector[T], val B: Connector[T]) {
  val sum  = new Connector({ A.value + B.value })
}

class Constant[T](var x: T) {
  val value = new Connector({ x })
}

class Connector[T](f: => T) {
  def value: T = f
  override def toString = value.toString()
}

object Main extends App{
  val n1 = new Constant(1)

  // works
  val n5 = new Constant(5)
  val a = new Arithmetic( n1.value, n5.value )
  println(a.sum)

 // no works
 val n55 = new Constant(5.5)
 val b = new Arithmetic( n1.value, n55.value )
 println(b.sum)

}

I've also tried

class Arithmetic[T,R : Numeric](val A: Connector[T], val B: Connector[R]) {

and several other combinations, but I ended up with

error: could not find implicit value for parameter num: scala.math.Numeric[Any]
val sum  = new Connector({ A.value + B.value })

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

烂柯人 2024-12-16 17:06:56

您看到的错误消息是因为 Numeric[T].plus 只能用于添加两个相同类型 T 的值。
您的代码是在数字加宽自动发生的假设下编写的 - 在这种情况下不会自动发生,因为编译器不知道有关类型的任何信息,除了存在 Numeric[T] 实例。

如果您需要 sum 为稳定值,则必须在构造函数中提供必要的类型信息,如下所示:

class Arithmetic[A : Numeric, R <% A, S <% A](val a: Connector[R], b: Connector[S]) {
  val sum = new Connector[A]((a.value:A) + (b.value:A))
}

这需要类型 RS 可转换为已知 Numeric[A] 距离的某种类型 A
创建实例时,您始终必须提供所有类型参数,因为它们无法推断。

如果您不需要 sum 保持稳定,您可以将您的类更改为:

class Arithmetic[A,B](val a: Connector[A], val b: Connector[B]) {

  // if A and B are the same types
  def sum(implicit e: B =:= A, n: Numeric[A]): Connector[A] =
    new Connector(n.plus(a.value, b.value))

  // else widen to C
  def wideSum[C](implicit f: A => C, g: B => C, n: Numeric[C]) =
    new Connector(n.plus(a.value, b.value))
}

val a = new Connector(1)

val b = new Connector(2)

val c = new Connector(3.0)

val d = (new Arithmetic(a,b)).sum

// val e = (new Arithmetic(b,c)).sum // <-- does not compile

val e = (new Arithmetic(b,c)).wideSum[Double]

当扩展时,您仍然需要提供类型信息。

The error message you are seeing is because Numeric[T].plus can only be used to add two values of the same type T.
Your code is written under the assumption that numeric widening happens automatically - which will not in this case as the compiler does not know anything about the types except that there exists a Numeric[T] instance.

If you need sum to be a stable value, you will have to provide the necessary type information in the constructor like this:

class Arithmetic[A : Numeric, R <% A, S <% A](val a: Connector[R], b: Connector[S]) {
  val sum = new Connector[A]((a.value:A) + (b.value:A))
}

This requires types R and S to be convertible into some type A for which a Numeric[A] istance is known.
When creating an instance you would always have to provide all type parameters as they cannot be inferred.

If you do not need sum to be stable you could change your class to this:

class Arithmetic[A,B](val a: Connector[A], val b: Connector[B]) {

  // if A and B are the same types
  def sum(implicit e: B =:= A, n: Numeric[A]): Connector[A] =
    new Connector(n.plus(a.value, b.value))

  // else widen to C
  def wideSum[C](implicit f: A => C, g: B => C, n: Numeric[C]) =
    new Connector(n.plus(a.value, b.value))
}

val a = new Connector(1)

val b = new Connector(2)

val c = new Connector(3.0)

val d = (new Arithmetic(a,b)).sum

// val e = (new Arithmetic(b,c)).sum // <-- does not compile

val e = (new Arithmetic(b,c)).wideSum[Double]

When widening you will still have to provide the type information though.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文