我在跟随一本书时在Scala中实现了List类型。
这是我的列表类型的定义:
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
所有后面提到的函数都在同一文件中的伴随对象List中定义
object List
我写了foldLeft
和foldRight
,如下所示
def foldLeft[A,B](l: List[A], z: B)(f: (B, A) => B): B = l match {
case Nil => z
case Cons(x, xs) => foldLeft(xs, f(z, x))(f)
}
def foldRight[A,B](l: List[A], z: B)(f: (A, B) => B): B = l match {
case Nil => z
case Cons(x, xs) => f(x, foldRight(xs, z)(f))
}
本书的练习是使用foldLeft
实施foldRight
。这是我最初的实施
def foldLeftWithRight[A,B](l: List[A], z: B)(f: (B, A) => B): B = {
foldRight(l, z)((a: A, b: B) => f(b, a))
}
然后我想如果我要使用foldRight
来实现foldLeft
,我应该编写另一个函数来执行反向参数。如下:
def reverseArgs[A,B](f: (A, B) => B): (B, A) => B = {
(b: B, a: A) => f(a, b)
}
所以我将foldLeftWithRight
的代码更改为以下内容:
def foldLeftWithRight[A,B](l: List[A], z: B)(f: (B, A) => B): B = {
foldRight(l, z)(reverseArgs(f))
}
IntelliJ正在抱怨reverseArgs(f)
:
类型不匹配:预期(A,B)=> B,实际(B,B)=>乙
当我尝试编译代码时,错误如下:
Error:(21, 37) type mismatch;
found : (B, A) => B
required: (B, Any) => Any
foldRight(l, z)(reverseArgs(f))
一个有趣的观察结果是,当我在reverseArgs
上使用foldRightWithLeft
时,根本就没有问题:
def foldRightWithLeft[A,B](l: List[A], z: B)(f: (A, B) => B): B = {
foldLeft(l, z)(reverseArgs(f))
}
这里发生了什么?
答案 0 :(得分:2)
如果您将reverseArgs
功能的类型参数重命名为X
和Y
,那么您将获得类似
def reverseArgs[X ,Y](f: (X, Y) => Y): (Y, X) => Y = ???
f
中的foldLeftWithRight
类型为(B, A) => B
。将其传递给reverseArgs
意味着:
X = B
Y = A
Y = B
我猜Intellij从这里推断出A = B,这就是为什么它抱怨(B, B) => B
不是(A, B) => B
。 Scalac决定Y = Any,因为它是两个可能不相关的类型的最小上限。
这里的好解决方案是概括更多。反转函数的返回类型不必是参数类型之一,因此您可以为其引入另一种泛型类型:
def reverseArgs[X ,Y, Z](f: (X, Y) => Z): (Y, X) => Z = {
(b: Y, a: X) => f(a, b)
}