Scala 为什么我必须在fold中写下匿名函数的返回类型

Scala 为什么我必须在fold中写下匿名函数的返回类型,scala,functional-programming,type-inference,Scala,Functional Programming,Type Inference,在Scala中给出以下代码: package fpinscala.datastructures sealed trait Tree[+A] case class Leaf[A](value: A) extends Tree[A] case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A] object Tree { def fold[A,B](t: Tree[A])(f: A => B)(g: (B,B)

在Scala中给出以下代码:

package fpinscala.datastructures
sealed trait Tree[+A]
case class Leaf[A](value: A) extends Tree[A]
case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]

object Tree {

  def fold[A,B](t: Tree[A])(f: A => B)(g: (B,B) => B): B = {
    t match {
      case Leaf(x) => f(x)
      case Branch(l,r) => g(fold(l)(f)(g),fold(r)(f)(g))
    }
  }

  def mapViaFold[A,B](t:Tree[A])(f: A => B): Tree[B] = {
    fold(t)(a => Leaf(f(a)): Tree[B])(Branch(_,_))
  }

}
为什么我必须写下函数的返回类型
a=>Leaf(f(a)):Tree[B]
?如果没有它,我会收到错误消息:

Error:(54, 36) type mismatch;
 found   : fpinscala.datastructures.Branch[B]
 required: fpinscala.datastructures.Leaf[B]
    fold(t)(a => Leaf(f(a)))(Branch(_,_))
                                   ^

因为在这种情况下,折叠定义中的类型参数
B
从术语
Leaf(f(a))
推断为
Leaf[B]
。然后,您的类型与
分支(,)
(叶[B],叶[B])=>分支[B]
的类型不匹配,这将永远不会是所需类型的子类型
(叶[B],叶[B])=>叶[B]

更新 我认为这种行为是由于Scala中类型重构的工作方式:它基于参数列表(而不是单个参数),并且从左到右进行。因此,一旦编译器能够推断参数列表的某些类型,它将使用它们来解析右侧参数列表的类型,而不是相反

下面我尝试以更简单的形式提取问题:

trait A
class B extends A
class C extends A

def f[T](x: T)(y: T): Int = 1
def g[T](x: T, y: T): Int = 1

f(new B)(new C) // Does not compile
g(new B, new C) // Compiles
在当前版本中,在第一个参数列表之后,
T
被推断为
B
,然后我们在第二个参数列表中得到一个类型错误


相反,在从容版本中,编译器使用唯一参数列表中的所有参数来推断T的类型,在本例中,这是我们所期望的最小上界A。

在这里找到了答案:为什么编译器不能找出叶[B]的超类型满足这两个表达式?我已经在更新部分用我认为是原因的内容更新了答案。