Generics 如何指定一个泛型函数,该函数的工作方式就好像存在Int、Double等超类型一样?
我需要定义一个类来保证基本的数字操作会出现(Generics 如何指定一个泛型函数,该函数的工作方式就好像存在Int、Double等超类型一样?,generics,math,scala,Generics,Math,Scala,我需要定义一个类来保证基本的数字操作会出现(+,-,*,…) 到目前为止还不错,但现在我强制T为同一类型。因此算术(double,int)将失败。我的实际应用程序甚至有点做作: class Arithmetic[T](A: Connector[T], B: Connector[U])(implicit n: Numeric[T]) { val sum = new Connector({ n.plus(A.value + B.value) }) } class Constant[T]
+
,-
,*
,…)
到目前为止还不错,但现在我强制T
为同一类型。因此算术(double,int)
将失败。我的实际应用程序甚至有点做作:
class Arithmetic[T](A: Connector[T], B: Connector[U])(implicit n: Numeric[T]) {
val sum = new Connector({ n.plus(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 )
// doesn't work
val n55 = new Constant(5.5)
val b = new Arithmetic( n1.value, n55.value )
}
想法?建议?我只需要一些东西来保证我能够在这个类中做基本的数学运算…你认为应该在这里使用吗
它至少对scala 2.9.1起作用
scala> arithmetic(1, 2.2)
res0: Double = 3.2
你喜欢这个工作吗
import Numeric.Implicits._
trait Add[A, B, Result] {
def plus(a: A, b: B): Result
}
trait LowerPriorityAdd {
implicit def addNumNum[M, N](implicit numM: Numeric[M], numN: Numeric[N]) = new Add[M, N, Double] {
def plus(m: M, n: N) = m.toDouble + n.toDouble
}
}
trait LowPriorityAdd {
implicit def addYX[X, Y, Z](implicit addXY: Add[X, Y, Z]) = new Add[Y, X, Z] {
def plus(y: Y, x: X) = addXY.plus(x, y)
}
}
object Add extends LowPriorityAdd with LowerPriorityAdd {
implicit object AddIntInt extends Add[Int, Int, Int] {
def plus(i: Int, j: Int) = i + j
}
implicit object AddIntDouble extends Add[Int, Double, Double] {
def plus(i: Int, d: Double) = i + d
}
}
class Arithmetic[T, U, V](t: Connector[T], u: Connector[U])(implicit ev: Add[T, U, V]) {
val sum: Connector[V] = new Connector(ev.plus(t.value, u.value))
}
class Constant[A](val x: A) {
val value: Connector[A] = new Connector(x)
}
class Connector[A](f: => A) {
def value: A = f
override def toString = value.toString
}
def main(args: Array[String]): Unit = {
val n1 = new Constant(1)
// works
val n5 = new Constant(5)
val a = new Arithmetic( n1.value, n5.value )
// works
val n55 = new Constant(5.5)
val b = new Arithmetic( n1.value, n55.value )
// works
val c = new Arithmetic(n55.value, n1.value)
}
这里有一个想法:
class BiConverter[T, U, That](val toThat1: T => That, val toThat2: U => That)(implicit val num: Numeric[That])
trait LowPriorityBiConverterImplicits {
implicit def subtype[A: Numeric, T <: A, U <: A]: BiConverter[T, U, A] = new BiConverter[T, U, A](identity, identity)
}
object BiConverter extends LowPriorityBiConverterImplicits {
implicit def identityConverter[T: Numeric]: BiConverter[T, T, T] = new BiConverter[T, T, T](identity, identity)
implicit def firstAsSecond[T, U](implicit conv: T => U, num: Numeric[U]): BiConverter[T, U, U] = new BiConverter[T, U, U](conv, identity)
implicit def secondAsFirst[T, U](implicit conv: U => T, num: Numeric[T]): BiConverter[T, U, T] = new BiConverter[T, U, T](identity, conv)
}
class Arithmetic[T] private (A: Connector[T], B: Connector[T])(implicit n: Numeric[T]) {
import Numeric.Implicits._
val sum = new Connector(A.value + B.value)
}
object Arithmetic {
def apply[T, U, That](A: Connector[T], B: Connector[U])(implicit conv: BiConverter[T, U, That], tIsThatEvidence: T =:= That = null, uIsThatEvidence: U =:= That = null): Arithmetic[That] = {
val newA: Connector[That] =
if (tIsThatEvidence != null) A.asInstanceOf[Connector[That]]
else new Connector(conv.toThat1(A.value))
val newB: Connector[That] =
if (uIsThatEvidence != null) B.asInstanceOf[Connector[That]]
else new Connector(conv.toThat2(B.value))
new Arithmetic(newA, newB)(conv.num)
}
}
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()
}
这与问题的说明不同是关于问题的第一部分(原始部分):)这不是最优的,因为它不能自动利用其他现有的数字转换…@Jean Philippellet:你确定它不能吗?查看
LowerPriorityAdd
trait中的隐式生成器。它可以很容易地扩展到其他数值运算中。问题不是它可以扩展:它甚至必须扩展。我认为我提出的解决方案不需要这个额外的步骤。哇,甚至连试图回答的一票都没有。OP非常慷慨。您不需要编写类似({x})
<代码>(x)就可以了。很好:-)你解决了我的问题,尽管解决方案看起来太大而且“不雅观”。。。无论如何,谢谢。:-)该解决方案与集合框架中使用的解决方案类似,该解决方案使用CanBuildFrom
隐式参数来确定map
操作的返回类型。@HugoSFerreira您是使用此参数关闭赏金,还是在寻找其他答案?我将关闭此赏金,虽然我更喜欢更少的代码。
scala> arithmetic(1, 2.2)
res0: Double = 3.2
import Numeric.Implicits._
trait Add[A, B, Result] {
def plus(a: A, b: B): Result
}
trait LowerPriorityAdd {
implicit def addNumNum[M, N](implicit numM: Numeric[M], numN: Numeric[N]) = new Add[M, N, Double] {
def plus(m: M, n: N) = m.toDouble + n.toDouble
}
}
trait LowPriorityAdd {
implicit def addYX[X, Y, Z](implicit addXY: Add[X, Y, Z]) = new Add[Y, X, Z] {
def plus(y: Y, x: X) = addXY.plus(x, y)
}
}
object Add extends LowPriorityAdd with LowerPriorityAdd {
implicit object AddIntInt extends Add[Int, Int, Int] {
def plus(i: Int, j: Int) = i + j
}
implicit object AddIntDouble extends Add[Int, Double, Double] {
def plus(i: Int, d: Double) = i + d
}
}
class Arithmetic[T, U, V](t: Connector[T], u: Connector[U])(implicit ev: Add[T, U, V]) {
val sum: Connector[V] = new Connector(ev.plus(t.value, u.value))
}
class Constant[A](val x: A) {
val value: Connector[A] = new Connector(x)
}
class Connector[A](f: => A) {
def value: A = f
override def toString = value.toString
}
def main(args: Array[String]): Unit = {
val n1 = new Constant(1)
// works
val n5 = new Constant(5)
val a = new Arithmetic( n1.value, n5.value )
// works
val n55 = new Constant(5.5)
val b = new Arithmetic( n1.value, n55.value )
// works
val c = new Arithmetic(n55.value, n1.value)
}
class BiConverter[T, U, That](val toThat1: T => That, val toThat2: U => That)(implicit val num: Numeric[That])
trait LowPriorityBiConverterImplicits {
implicit def subtype[A: Numeric, T <: A, U <: A]: BiConverter[T, U, A] = new BiConverter[T, U, A](identity, identity)
}
object BiConverter extends LowPriorityBiConverterImplicits {
implicit def identityConverter[T: Numeric]: BiConverter[T, T, T] = new BiConverter[T, T, T](identity, identity)
implicit def firstAsSecond[T, U](implicit conv: T => U, num: Numeric[U]): BiConverter[T, U, U] = new BiConverter[T, U, U](conv, identity)
implicit def secondAsFirst[T, U](implicit conv: U => T, num: Numeric[T]): BiConverter[T, U, T] = new BiConverter[T, U, T](identity, conv)
}
class Arithmetic[T] private (A: Connector[T], B: Connector[T])(implicit n: Numeric[T]) {
import Numeric.Implicits._
val sum = new Connector(A.value + B.value)
}
object Arithmetic {
def apply[T, U, That](A: Connector[T], B: Connector[U])(implicit conv: BiConverter[T, U, That], tIsThatEvidence: T =:= That = null, uIsThatEvidence: U =:= That = null): Arithmetic[That] = {
val newA: Connector[That] =
if (tIsThatEvidence != null) A.asInstanceOf[Connector[That]]
else new Connector(conv.toThat1(A.value))
val newB: Connector[That] =
if (uIsThatEvidence != null) B.asInstanceOf[Connector[That]]
else new Connector(conv.toThat2(B.value))
new Arithmetic(newA, newB)(conv.num)
}
}
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()
}
val n1 = new Constant(1)
val n5 = new Constant(5)
val a = Arithmetic(n1.value, n5.value)
val sum1 = a.sum.value // Int
println(sum1)
val n55 = new Constant(5.5)
val b = Arithmetic(n1.value, n55.value)
val sum2 = b.sum.value // Double
println(sum2)
val nBig5 = new Constant(BigInt(5))
val c = Arithmetic(n1.value, nBig5.value)
val sum3 = c.sum.value // BigInt
println(sum3)