I work with a class class of complex classes in Scala and would like to create an add function that works between complex numbers, doubles and ints. The following is a simple example of a working solution:
case class Complex(re: Double, im: Double) implicit def toComplex[A](n: A)(implicit f: A => Double): Complex = Complex(n, 0) implicit class NumberWithAdd[A](n: A)(implicit f: A => Complex) { def add(m: Complex) = Complex(n.re + m.re, n.im + m.im) }
Note. I intentionally do not include the add function in the complex case class. Using the above, I can do all of this:
scala> val z = Complex(1, 2); val w = Complex(2, 3) z: Complex = Complex(1.0,2.0) w: Complex = Complex(2.0,3.0) scala> z add w res5: Complex = Complex(3.0,5.0) scala> z add 1 res6: Complex = Complex(2.0,2.0) scala> 1 add z res7: Complex = Complex(2.0,2.0)
I would like to use '+' instead of 'add, but this does not work. I get the following error:
Error:(14, 4) value + is not a member of A$A288.this.Complex z + 1 ^
Both z + w and 1 + z still work.
What would I like to know why changing a function name from 'add' to '+' violates this? Is there an alternative way to get this functionality (without just adding the add function to the complex case class)? Any help would be appreciated.
Change - Motivation
I play with monoids and other algebraic structures. I would like to be able to generalize the "... WithAdd" function to automatically work for any class with the corresponding monoid:
trait Monoid[A] { val identity: A def op(x: A, y: A): A } implicit class withOp[A](n: A)(implicit val monoid: Monoid[A]) { def +(m: A): A = monoid.op(n, m) } case class Complex(re: Double, im: Double) { override def toString: String = re + " + " + im + "i" } class ComplexMonoid extends Monoid[Complex] { val identity = Complex(0, 0) def op(z: Complex, w: Complex): Complex = { Complex(z.re + w.re, z.im + w.im) } } implicit val complexMonoid = new ComplexMonoid
Using the above, I can now do Complex(1, 2) + Complex(3, 1) , giving Complex = 4.0 + 3.0i . This is great for reusing code, since now I can add additional functions for the Monoid and withAdd functions (for example, resorting to an element from time to time, providing a power function for multiplication), and this will work for any case class that has the corresponding monoid, Only with complex numbers and trying to include doubles, ints, etc., I then ran into the problem above.