为了编写DSL,我想对算术运算进行建模。
在Int
和Double
上的乘法运算显然应该导致Double
,在Int
和Int
上它应该导致整数等等。
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)
答案 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/Double
,Double/Int
,Int/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)
(我想,这两个是解决分隔问题所需的全部内容)