ost*_*lop 9 types scala numeric
我想实现一个类C
来存储各种数值类型的值,以及布尔值.此外,我想能够在这个类的实例操作,类型之间,转换在必要Int --> Double
和Boolean -> Int
,即,能够添加Boolean + Boolean
,Int + Boolean
,Boolean + Int
,Int + Double
,Double + Double
等等,返回最小的可能类型(Int
或Double
可能的),只要.
到目前为止,我想出了这个:
abstract class SemiGroup[A] { def add(x:A, y:A):A }
class C[A] (val n:A) (implicit val s:SemiGroup[A]) {
def +[T <% A](that:C[T]) = s.add(this.n, that.n)
}
object Test extends Application {
implicit object IntSemiGroup extends SemiGroup[Int] {
def add(x: Int, y: Int):Int = x + y
}
implicit object DoubleSemiGroup extends SemiGroup[Double] {
def add(x: Double, y: Double):Double = x + y
}
implicit object BooleanSemiGroup extends SemiGroup[Boolean] {
def add(x: Boolean, y: Boolean):Boolean = true;
}
implicit def bool2int(b:Boolean):Int = if(b) 1 else 0
val n = new C[Int](10)
val d = new C[Double](10.5)
val b = new C[Boolean](true)
println(d + n) // [1]
println(n + n) // [2]
println(n + b) // [3]
// println(n + d) [4] XXX - no implicit conversion of Double to Int exists
// println(b + n) [5] XXX - no implicit conversion of Int to Boolean exists
}
Run Code Online (Sandbox Code Playgroud)
这适用于某些情况(1,2,3)但不适用于(4,5).原因是类型从低到高隐含地扩大,而不是另一种方式.在某种程度上,该方法
def +[T <% A](that:C[T]) = s.add(this.n, that.n)
Run Code Online (Sandbox Code Playgroud)
不知何故需要有一个看起来像这样的伙伴方法:
def +[T, A <% T](that:C[T]):T = that.s.add(this.n, that.n)
Run Code Online (Sandbox Code Playgroud)
但这不能编译有两个原因,首先是编译器无法转换this.n
为类型T
(即使我们指定了视图绑定A <% T
),其次,即使它能够转换this.n
,在类型擦除后,这两种+
方法也变得模糊不清.
对不起,这么久.任何帮助将非常感激!否则,我似乎必须明确地写出所有类型之间的所有操作.如果我必须添加额外的类型(Complex
菜单上的下一个......),它会变得毛茸茸.
也许有人有另一种方法可以完全实现这一切?感觉就像我有一些简单的东西.
提前致谢!
好的,丹尼尔!
我已经限制了解决方案忽略布尔,只有用工作AnyVals
有微弱的最小上限具有的一个实例Numeric
.这些限制是任意的,你可以删除它们并编码你自己的类型之间的弱一致性关系 - 执行a2b
和a2c
可以执行一些转换.
有趣的是考虑隐式参数如何模拟继承(传递类型(Derived => Base)或弱一致性的隐式参数.它们非常强大,特别是当类型推断器帮助你时).
首先,我们需要一个类型的类来表示弱最小上界所有对类型的A
和B
,我们感兴趣的内容.
sealed trait WeakConformance[A <: AnyVal, B <: AnyVal, C] {
implicit def aToC(a: A): C
implicit def bToC(b: B): C
}
object WeakConformance {
implicit def SameSame[T <: AnyVal]: WeakConformance[T, T, T] = new WeakConformance[T, T, T] {
implicit def aToC(a: T): T = a
implicit def bToC(b: T): T = b
}
implicit def IntDouble: WeakConformance[Int, Double, Double] = new WeakConformance[Int, Double, Double] {
implicit def aToC(a: Int) = a
implicit def bToC(b: Double) = b
}
implicit def DoubleInt: WeakConformance[Double, Int, Double] = new WeakConformance[Double, Int, Double] {
implicit def aToC(a: Double) = a
implicit def bToC(b: Int) = b
}
// More instances go here!
def unify[A <: AnyVal, B <: AnyVal, C](a: A, b: B)(implicit ev: WeakConformance[A, B, C]): (C, C) = {
import ev._
(a: C, b: C)
}
}
Run Code Online (Sandbox Code Playgroud)
该方法unify
返回type C
,类型inferencer根据隐式值的可用性计算出来,以提供隐式参数ev
.
我们可以将它插入你的包装器类C,如下所示,也需要一个,Numeric[WeakLub]
所以我们可以添加值.
case class C[A <: AnyVal](val value:A) {
import WeakConformance.unify
def +[B <: AnyVal, WeakLub <: AnyVal](that:C[B])(implicit wc: WeakConformance[A, B, WeakLub], num: Numeric[WeakLub]): C[WeakLub] = {
val w = unify(value, that.value) match { case (x, y) => num.plus(x, y)};
new C[WeakLub](w)
}
}
Run Code Online (Sandbox Code Playgroud)
最后,把它们放在一起:
object Test extends Application {
val n = new C[Int](10)
val d = new C[Double](10.5)
// The type ascriptions aren't necessary, they are just here to
// prove the static type is the Weak LUB of the two sides.
println(d + n: C[Double]) // C(20.5)
println(n + n: C[Int]) // C(20)
println(n + d: C[Double]) // C(20.5)
}
Test
Run Code Online (Sandbox Code Playgroud)