在尾递归函数中使用Nil作为初始累加器

7 浏览
0 Comments

在尾递归函数中使用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]

0
0 Comments

问题出现的原因是,Scala的类型推断是从第一个参数列表开始的。所以给定def foldLeft[B](z: B)(f: (B, A) => B): Bxs.foldLeft(Nil)(...),它将B推断为Nil.type(只有一个值的类型:Nil),并使用这个类型来检查第二个参数列表,显然会失败。然而,List[String]()的类型是List[String],因此BList[String],这将与f正常工作。另一种解决方法是显式地写出类型参数:xs.foldLeft[List[String]](Nil)(...)。在第二个程序中,acc的类型是给定的(也必须是给定的,因为它是一个函数参数),所以不会发生与你最初问题相对应的类型推断。

0