我对Scala很新。我想写几个数学对象(Complex,Polynomial等),这些对象在某些操作(+, - ,*)下是封闭的,它们可以在泛型中使用,并且可以使用隐式强制转换。
我似乎已经解决了第一点。
trait GroupUnderAddition[T] {
def + (t : T) : T
}
case class Real(d : Double) extends GroupUnderAddition[Real] {
def + (r : Real) = Real(d + r.d)
}
case class Complex(re : Double, im : Double) extends GroupUnderAddition[Complex] {
def + (c : Complex) = Complex(re + c.re, im + c.im)
}
object Test {
implicit def real_to_complex(r : Real) = Complex(r.d, 0)
def test[G <: GroupUnderAddition[G]](a : G, b : G) = a + b
def main(args : Array[String]) {
println(test(Real(5), Real(2)))
}
}
现在,我如何编写test()以便
test(Real(5), Complex(2, 1))
返回Complex(7,1)?
答案 0 :(得分:2)
主要思想是所有GroupUnderAddition都不兼容,所以当你似乎想要使用复杂代数时,我建议建立一个包含GoupUnderAddition的超类。但是,建议不要将其作为案例类(如果case class
延长case class
,请参阅警告
trait GroupUnderAddition[T] {
def + (t : T) : T
}
class ComplexAlgebra(_re:Double, _im:Double) extends(GroupUnderAddition[ComplexAlgebra]) {
val re = _re
val im = _im
def + (c : ComplexAlgebra) = new ComplexAlgebra(re + c.re, im + c.im)
}
case class Real(d : Double) extends ComplexAlgebra(d, 0)
case class Complex(real : Double, imaginary : Double) extends ComplexAlgebra(real,imaginary)
object Test {
def test(a : ComplexAlgebra, b : ComplexAlgebra) = a + b
def main(args : Array[String]) {
println(test(Real(5), Real(2)))
}
}
答案 1 :(得分:1)
问题在于implicit def
不考虑参数转换,除非您指定方法定义来执行此操作。
因此,如果你有Real(5).foo
和foo
这样的内容只定义为复杂,那么implicit def
将适用于此。
如果您使用的方法如下:def foo(c : Complex) = ...
,则不能使用foo(Real(5))
来调用它。
如果要应用隐式转换,则必须指定方法,以便可以转换其参数。对于上述foo
方法,您可以这样做:
def foo[T](c : T)(implicit ct : T => Complex) = ...`
然后调用foo(Real(5))
是有效的,并且将使用转换。
根据您的具体问题,您可以编写如下测试方法:
def test[G <: GroupUnderAddition[G],T](a : T, b : G)(implicit ag: T => G) = a + b
通过指定,应考虑从T
到G
的隐式转化,您允许test
方法现在接受test(Real(5), Complex(2,1))
。
但是,它不会反过来。所以你还不能用test(Complex(2,1), Real(5))
来调用它,因为第二个参数没有隐式转换。
考虑这两种转换的简单方法就是这样写:
def test[G <: GroupUnderAddition[G],T1, T2](a : T1, b : T2)(implicit ag: T1 => G, bg: T2 => G) = a + b
不幸的是,编译器在调用此方法时会以某种方式为Any
派生G
。我现在还不知道,如何解决这个问题,我发布了这个答案,希望别人可以填写这最后一块拼图。
鉴于上述最终定义,您可以在指定完整类型时至少以任一方式调用该方法:
println(test[Complex,Real,Complex](Real(5), Complex(2, 1)))
println(test[Complex,Complex,Real](Complex(2,1), Real(5)))
答案 2 :(得分:1)
这里真正的问题是,你正在做出(错误的)假设test(Real(5), Complex(2, 1))
以任何方式明确定义,给定你所写的内容。请考虑以下事项:
case class Word(s : String) extends GroupUnderAddition[Word] {
def +(w : Word) = Word(s + w.s)
}
这完全满足您对'GroupUnderAddition'的定义,但尝试向Real(2)添加Word(“Hello”)是没有意义的。结果是什么?
您尝试编码的是更大域中的特定加法运算符 - 它似乎是C上多项式的域 - 并且指定在加法运算符下关闭它的某些子组。 ChrisJamesC的方法可以很好地扩展到多项式环,它可以捕获你想要的东西。