Scala将泛型函数传递给另一个泛型函数混淆

时间:2017-07-20 07:24:41

标签: scala generics functional-programming

我在跟随一本书时在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

我写了foldLeftfoldRight,如下所示

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))
}

这里发生了什么?

1 个答案:

答案 0 :(得分:2)

如果您将reverseArgs功能的类型参数重命名为XY,那么您将获得类似

的内容
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)
}