在尾递归函数中使用Nil作为初始累加器
在尾递归函数中使用Nil作为初始累加器
Daniel Sobral先生 在这里回答说Nil
不能用作fold
的初始累加器。在使用Nil
作为初始累加器值时无法工作。
scala> xs res9: List[Int] = List(1, 2, 3) scala> xs.foldLeft(Nil)( (acc, elem) => elem.toString :: acc):9: error: type mismatch; found : List[String] required: scala.collection.immutable.Nil.type xs.foldLeft(Nil)( (acc, elem) => elem.toString :: acc)
但是如果我传入List[String]()
,它就能工作。
scala> xs.foldLeft(List[String]())( (acc, elem) => elem.toString :: acc) res7: List[String] = List(3, 2, 1)
然而,为什么我可以在下面的尾递归函数中使用Nil
?
scala> def toStringList(as: List[Int]): List[String] = { | def go(bs: List[Int], acc: List[String]): List[String]= bs match { | case Nil => acc | case x :: xs => go(xs, x.toString :: acc) | } | println(as) | go(as, Nil) | } toStringList: (as: List[Int])List[String]
问题出现的原因是,Scala的类型推断是从第一个参数列表开始的。所以给定def foldLeft[B](z: B)(f: (B, A) => B): B
和xs.foldLeft(Nil)(...)
,它将B
推断为Nil.type
(只有一个值的类型:Nil
),并使用这个类型来检查第二个参数列表,显然会失败。然而,List[String]()
的类型是List[String]
,因此B
是List[String]
,这将与f
正常工作。另一种解决方法是显式地写出类型参数:xs.foldLeft[List[String]](Nil)(...)
。在第二个程序中,acc
的类型是给定的(也必须是给定的,因为它是一个函数参数),所以不会发生与你最初问题相对应的类型推断。