多态性在scala中没有按预期工作

时间:2016-03-06 07:07:21

标签: scala

我在object List中声明了两个方法:

def reduce[A, B >: A](l: List[A])(f: (B, B) => B): B =
  reduceLeft(l)(f)

def reduceLeft[A, B >: A](l: List[A])(op: (B, A) => B): B = ???

我借用了scala.collection.TraversableOnce班级的签名。 (由于教学原因,我正在重新创建自己的课程。)

编译器给我这个错误:

[error] /.../List.scala:159: type mismatch;
[error]  found   : (B, B) => B
[error]  required: (A, A) => A
[error]     reduceLeft(l)(f)
[error]                   ^ 

我的List类是

final case class ::[A](head: A, tail: List[A]) extends List[A] {
  override def isEmpty: Boolean = false
}

sealed trait List[+A] {
  def head: A

  def tail: List[A]

  def isEmpty: Boolean

  def ::[B >: A](x: B): List[B] =
    datastructures.::(x, this)
}

TraversableOnce定义怎么能逃脱这个?是否与我没有将该方法定义为中缀操作有关?

sealed trait List[+A] {
  ...
  def reduce(op: (B,B) => B):B = reduceLeft(op) // e.g.
  ... //reduceLeft...
}

更新

我已经尝试过TraversableOnce类在中缀中声明特性并且它似乎有效(见下文),但是我仍然很好奇为什么对象定义不起作用。

sealed trait List[+A] {
  ...
  def reduce[B >: A](f: (B, B) => B): B =
    self.reduceLeft(f)

  def reduceLeft[B >: A](op: (B, A) => B): B = {
    if (isEmpty)
      throw new UnsupportedOperationException("empty.reduceLeft")

    var first = true
    var acc: B = 0.asInstanceOf[B]

    for (x <- self) {
      if (first) {
        acc = x
        first = false
      }
      else acc = op(acc, x)
    }
    acc
  }

  @tailrec
  final def foreach[U](f: A => U): Unit = { f(head); tail.foreach(f); }
  ...
}

1 个答案:

答案 0 :(得分:8)

以下是这里发生的事情:当您致电reduceLeft(l)(f)时,您首先使用reduceLeft(l)致电l: List[A]。由于你的reduceLeft有两个类型参数,但你没有明确指定它们,到目前为止它只有A可以使用。因此,编译器尽可能地推断出类型,使用A 两种类型。您可以通过将此部分应用程序提取到变量中来查看:

val partiallyApplied: ((A, A) => A) => A = reduceLeft(l)

然后,当您使用f: (B, B) => B应用第二个参数列表时,类型不匹配。

修复很简单 - 在调用reduceLeft时明确说明类型:

def reduce[A, B >: A](l: List[A])(f: (B, B) => B): B = {
  reduceLeft[A, B](l)(f)
}