在Scala中是否可以动态传递通用类型?

时间:2018-07-18 15:11:25

标签: scala types

为了编写DSL,我想对算术运算进行建模。

IntDouble上的乘法运算显然应该导致Double,在IntInt上它应该导致整数等等。

scala中是否有任何方法可以确定类型并将其动态传递?在下面的代码中,我添加了作为示例的功能调用arithmeticReturnType(TL,TR),然后应将其替换为可在Scala中实际使用的功能。

trait NumericCol[Repr]

case class Divide[R](l: NumericCol[_], r: NumericCol[_]) extends NumericCol[R]

def divide[TL,TR](left: NumericCol[TL], right: NumericCol[TR]) = Divide[**arithmeticReturnType(TL,TR)**](left, right)

2 个答案:

答案 0 :(得分:4)

如果您曾经研究过scala集合的实现方式,那么您可能已经注意到所有用于确定集合操作最具体返回类型的“ CanBuildFrom”东西。您可以应用相同的技巧来确保DSL中的类型安全:

trait CanDivideInto[A, B, C] {
  def divide(a: A, b: B): C
}

implicit object DoubleIntCanDivideIntoDouble 
extends CanDivideInto[Double, Int, Double] {
  def divide(a: Double, b: Int): Double = a / b
}

implicit object InIntCanDivideIntoInt
extends CanDivideInto[Int, Int, Int] {
  def divide(a: Int, b: Int): Int = a / b
}

trait NumericCol[Repr]

case class Divide[A, B, C](
  l: NumericCol[A], 
  r: NumericCol[B], 
  divider: CanDivideInto[A, B, C]
) extends NumericCol[C]

def divide[A, B, C](
  left: NumericCol[A], 
  right: NumericCol[B]
)(implicit div: CanDivideInto[A, B, C]): NumericCol[C] = 
  Divide[A, B, C](left, right, div)

val a = new NumericCol[Double]{}
val b = new NumericCol[Int]{}

val c: NumericCol[Double] = divide(a, b)
// val nope: NumericCol[Int] = divide(a, b) // won't compile, good.

Int/DoubleDouble/IntInt/Int等不同的情况可能会导致一些样板,但我看不出有什么办法,因为将整数除以双精度或整数浮点数或整数 应该在一天结束时导致不同的汇编指令...

答案 1 :(得分:-1)

类型类是一种可能性,但是在这种情况下,我不明白为什么不只使用函数重载。它完成了这项工作,并节省了一堆样板:

def divide(a: NumericColumn[Int], b: NumericColumn[Int]) = Divide[Int](a,b)
def divide(a: NumericColumn[Double], b: NumericColumn[Double]) = Divide[Double](a,b)

(我想,这两个是解决分隔问题所需的全部内容)