我正在使用Scala中一个简单的复数案例类,并希望创建一个在复数,双精度和整数之间工作的add函数。以下是工作解决方案的简单示例:
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)
}
注意我故意不在复杂案例类中包含add函数。使用上面我可以完成所有这些:
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)
我想使用' +'而不是添加,但这不起作用。我收到以下错误:
Error:(14, 4) value + is not a member of A$A288.this.Complex
z + 1
^
然而,z + w
和1 + z
仍然有用。
我想知道的是为什么更改功能名称来添加'到' +'打破这个?是否有另一种获得此功能的途径(不需要简单地将add函数放在复杂的case类中)?任何帮助将不胜感激。
我正在玩幺半群和其他代数结构。我希望能够概括一下......&Withgd'函数自动适用于具有相应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
使用上述内容,我现在可以Complex(1, 2) + Complex(3, 1)
提供Complex = 4.0 + 3.0i
。这对于代码重用非常有用,因为我现在可以向Monoid和withAdd函数添加额外的函数(例如,将元素应用于元素,给出乘法的幂函数),它适用于任何具有相应monoid的case类。只有复杂的数字,并试图合并双打,整数等,然后我遇到上面的问题。
答案 0 :(得分:0)
我会使用常规class
,而不是case class
。然后,很容易创建添加或减去这些复数的方法,例如:
class Complex(val real : Double, val imag : Double) {
def +(that: Complex) =
new Complex(this.real + that.real, this.imag + that.imag)
def -(that: Complex) =
new Complex(this.real - that.real, this.imag - that.imag)
override def toString = real + " + " + imag + "i"
}
正如the source page所示,它现在将支持看起来像运算符重载的内容(不是,因为+
和-
是函数而不是运算符)。
implicit class NumberWithAdd
及其方法+
的问题在于,Int
和Double
等数字类中也存在相同的方法。 +
NumberWithAdd
方法基本上允许您从可以转换为Complex
的数字开始,并将Complex
对象添加到第一个项目。也就是说,左手值可以是任何值(只要它可以被转换),右手值必须是Complex
。
这适用于w + z
(无需转换w
)和1 + z
(Int
到Complex
的隐式转换可用)。它因z + 1
而失败,因为+
在类Complex
中不可用。
由于z + 1
实际上是z.+(1)
,因此Scala会在+(i: Int)
可以转换为的类中查找Complex
的其他可能匹配项。它还会检查NumberWithAdd
,它具有+
功能,但需要Complex
作为右手值。 (它会匹配一个需要Int
作为右手值的函数。)还有一些名为+
的函数接受Int
,但没有从Complex
到+
的转换那些功能想要什么作为左手值。
Complex
的相同定义在(case)类w + z
中起作用。在这种情况下,z + 1
和1 + z
都只使用该定义。案例Int
现在有点复杂了。由于+
没有接受Complex
值的函数Complex
,因此Scala会找到(Int
)中的值,并确定是否可以将Complex
转换为+
。这可以使用隐式函数,转换发生并执行函数。
当班级NumberWithAdd
中的add
函数重命名为Int
时,Int
中的函数不会混淆,因为+
没有函数{ {1}}。因此,Scala将更加努力地应用函数add
,它将执行Int
到Complex
转换。当您尝试1 add 2
时,它甚至会进行转换。
注意:我的解释可能无法完整描述实际的内部运作。