Scala 为什么我必须在fold中写下匿名函数的返回类型
在Scala中给出以下代码: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)
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]的超类型满足这两个表达式?我已经在更新部分用我认为是原因的内容更新了答案。