实施数字

时间:2012-02-12 10:50:31

标签: generics scala

我对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)?

3 个答案:

答案 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).foofoo这样的内容只定义为复杂,那么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

通过指定,应考虑从TG的隐式转化,您允许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的方法可以很好地扩展到多项式环,它可以捕获你想要的东西。