我在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); }
...
}
答案 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)
}