Implementing numbers
I'm quite new to Scala. I want to write several mathematical objects (Complex, Polynomial, etc.) which are closed under some operations (+, -, *) in a way that they can be used in generics and implicit casts can be used.
I seem to have solved the first bit.
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)))
}
}
Now, how can I write test() so that
test(Real(5), Complex(2, 1))
returns Complex(7, 1) ?
The main idea is that all GroupUnderAddition are not compatible, so as you seem to be wanting to work with complex algebra, I would suggest to build a superclass including GoupUnderAddition. However it is not recommended to make it a case class (see warnings if you have a case class
extending a 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)))
}
}
The problem is that the implicit def
is not considered for argument conversion, unless you specify the method definition to do so.
Hence, if you have something like Real(5).foo
and foo
is only defined for complex, the implicit def
will work for that.
If you have a method like: def foo(c : Complex) = ...
you may not call it with foo(Real(5))
instead.
If you want to apply implicit conversion, you must specify your method such that its arguments may be converted. For the above foo
method you could do it like this:
def foo[T](c : T)(implicit ct : T => Complex) = ...`
Then it is valid to call foo(Real(5))
and the conversion will be used.
Adapted to your specific problem, you could write the test method like this:
def test[G <: GroupUnderAddition[G],T](a : T, b : G)(implicit ag: T => G) = a + b
By specifying, that implicit conversions from T
to G
shall be taken into account, you allow the test
method to now accept test(Real(5), Complex(2,1))
.
However, it will not work the other way round yet. So you cannot yet call it with test(Complex(2,1), Real(5))
, because there is no implicit conversion of the second argument.
A straightforward way to account for both conversion would be to write it like this:
def test[G <: GroupUnderAddition[G],T1, T2](a : T1, b : T2)(implicit ag: T1 => G, bg: T2 => G) = a + b
Unfortunately, the compiler somehow derives Any
for G
when calling this method like above. I don't know right now, how to resolve this problem and I posted this answer in the hope that someone else might fill in this last piece of the puzzle.
Given the above final definition you can at least call the method in either way, when specifying the full types:
println(test[Complex,Real,Complex](Real(5), Complex(2, 1)))
println(test[Complex,Complex,Real](Complex(2,1), Real(5)))
The real problem here is that you're making the (incorrect) assumption that test(Real(5), Complex(2, 1))
is well-defined in any way, given what you've written. Consider the following:
case class Word(s : String) extends GroupUnderAddition[Word] {
def +(w : Word) = Word(s + w.s)
}
This perfectly satisfies your definition of 'GroupUnderAddition', but it makes no sense to try to add a Word("Hello") to a Real(2). What's the result?
What you are trying to encode is a specific addition operator within a larger domain - it seems the domain of polynomials over C - and specifying that certain subgroups of this are closed under the addition operator. ChrisJamesC's approach could happily be extended to the polynomial ring, which would capture what you wanted.
链接地址: http://www.djcxy.com/p/57564.html上一篇: 隐式与显式接口
下一篇: 实现数字