Scala隐式转换函数名称冲突

时间:2016-04-05 20:08:48

标签: scala implicit-conversion

我正在使用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 + w1 + 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类。只有复杂的数字,并试图合并双打,整数等,然后我遇到上面的问题。

1 个答案:

答案 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及其方法+的问题在于,IntDouble等数字类中也存在相同的方法。 + NumberWithAdd方法基本上允许您从可以转换为Complex的数字开始,并将Complex对象添加到第一个项目。也就是说,左手值可以是任何值(只要它可以被转换),右手值必须是Complex

这适用于w + z(无需转换w)和1 + zIntComplex的隐式转换可用)。它因z + 1而失败,因为+在类Complex中不可用。 由于z + 1实际上是z.+(1),因此Scala会在+(i: Int)可以转换为的类中查找Complex的其他可能匹配项。它还会检查NumberWithAdd,它具有+功能,但需要Complex作为右手值。 (它会匹配一个需要Int作为右手值的函数。)还有一些名为+的函数接受Int,但没有从Complex+的转换那些功能想要什么作为左手值。

Complex的相同定义在(case)类w + z中起作用。在这种情况下,z + 11 + z都只使用该定义。案例Int现在有点复杂了。由于+没有接受Complex值的函数Complex,因此Scala会找到(Int)中的值,并确定是否可以将Complex转换为+。这可以使用隐式函数,转换发生并执行函数。

当班级NumberWithAdd中的add函数重命名为Int时,Int中的函数不会混淆,因为+没有函数{ {1}}。因此,Scala将更加努力地应用函数add,它将执行IntComplex转换。当您尝试1 add 2时,它甚至会进行转换。

注意:我的解释可能无法完整描述实际的内部运作。