在类中使用隐式对象

Joe*_*Joe 8 scala implicit

我正在尝试编写代码来表示Scala中的多项式.我需要这个代码是类型多态,所以我使用implicits来处理不同的类型.我有:

case class Mono[T](degree: Int, coeff: T) {
  def Degree: Int = return degree
  def Coeff: T = return coeff
}

class Poly[T](private val terms: List[Mono[T]]) {

  trait Semiring[T] {
    def add(x:T, y:T): T
    def mul(x:T, y:T): T
    def exponent(x: T, n:Int): T
    val unitA: T
  }

  implicit object IntSemiring extends Semiring[Int] {
    def add(x: Int, y: Int): Int = x+y
    def mul(x: Int, y: Int): Int = x*y
    def exponent(x: Int, n:Int): Int = if(n==0) 1 else x*exponent(x, n-1)
    val unitA: Int = 0
  }

  implicit object SetSemiring extends Semiring[Set[Int]] {
    def add(x: Set[Int], y: Set[Int]): Set[Int] = x.union(y)
    def mul(x: Set[Int], y: Set[Int]): Set[Int] = x.intersect(y)
    def exponent(x: Set[Int], n: Int): Set[Int] = x
    val unitA: Set[Int] = Set()
  }

  def eval(x: T)(implicit r: Semiring[T]): T = {
    var termlist = terms
    var sum = r.unitA
    var expression = terms
    while(!termlist.isEmpty) {
      val term = expression.head
      val power = r.exponent(x, term.Degree)
      val termval = r.mul(power, term.Coeff)
      sum = r.add(sum, termval)
      termlist = termlist.tail
    }
    return sum
  }      

  def add(that: Poly[T])(implicit r: Semiring[T]): Poly[T] = ...

  def mul(that: Poly[T])(implicit r: Semiring[T]): Poly[T] = ...
}
Run Code Online (Sandbox Code Playgroud)

为了简洁起见,我删除了一些功能.这编译很好,但当我尝试使用它时,我得到一些奇怪的错误:

scala> val p1 = new Poly(List(Mono(0,1),Mono(1,2),Mono(2,1)))
p1: Poly[Int] = Poly@450ae3fb
scala> p1 eval 3
<console>:9: error: could not find implicit value for parameter r: p1.Semiring[Int]
              p1 eval 3
                 ^
Run Code Online (Sandbox Code Playgroud)

我不确定如何解决它.我在错误的地方定义了隐含的对象吗?我尝试将它们移到课外但是编译器失败了.为了让它正常工作,我还需要做些什么吗?

Ste*_*lon 16

隐式解析在您调用函数的位置完成,而不是在您定义它的位置.你应该在调用之前导入你的implicits p1.eval:

val p1 = new Poly(List(Mono(0,1),Mono(1,2),Mono(2,1)))
import p1._
p1 eval 3
Run Code Online (Sandbox Code Playgroud)

由于您的implicits并未真正绑定到Poly的实例,因此您可以在Poly之外定义它们.

如果您不想明确导入Semiringimplicits,则可以在SemiringScala搜索的伴随对象中定义它们,以便在缺少对象对象时匹配implicits:

case class Mono[T](degree: Int, coeff: T) {
  def Degree: Int = return degree
  def Coeff: T = return coeff
}

class Poly[T](private val terms: List[Mono[T]]) {
  def add(that: Poly[T])(implicit r: Semiring[T]): Poly[T] = ...

  def mul(that: Poly[T])(implicit r: Semiring[T]): Poly[T] = ...
}

trait Semiring {
    def add(x:T, y:T): T
    def mul(x:T, y:T): T
    def exponent(x: T, n:Int): T
    val unitA: T
}

object Semiring {
  implicit object IntSemiring extends Semiring[Int] {
    def add(x: Int, y: Int): Int = x+y
    def mul(x: Int, y: Int): Int = x*y
    def exponent(x: Int, n:Int): Int = if(n==0) 1 else x*exponent(x, n-1)
    val unitA: Int = 0
  }

  implicit object SetSemiring extends Semiring[Set[Int]] {
    def add(x: Set[Int], y: Set[Int]): Set[Int] = x.union(y)
    def mul(x: Set[Int], y: Set[Int]): Set[Int] = x.intersect(y)
    def exponent(x: Set[Int], n: Int): Set[Int] = x
    val unitA: Set[Int] = Set()
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你不再需要导入它们了:

val p1 = new Poly(List(Mono(0,1),Mono(1,2),Mono(2,1)))
p1 eval 3
Run Code Online (Sandbox Code Playgroud)