为什么reduceLeft抱怨类型不匹配?

时间:2012-03-31 17:41:45

标签: scala

我试图找到一系列行中最长行的长度。

  val lines = Source.fromFile(args(0)).getLines() //a collection of strings
  val longestLine = lines.reduceLeft( (a,b) =>
      if(a.length > b.length) a.length else b.length )

但是这会导致以下错误:

/home/jesvin/dev/scala/readfile.scala:11: error: type mismatch;
 found   : Int
 required: String
      if(a.length > b.length) a.length else b.length )
                                ^
/home/jesvin/dev/scala/readfile.scala:11: error: type mismatch;
 found   : Int
 required: String
      if(a.length > b.length) a.length else b.length )
                                              ^
two errors found

我在某些位置尝试了一些显式的返回语句和类型转换,但它没有用。

我使用reduceLeft错了吗?

2 个答案:

答案 0 :(得分:11)

  

我使用reduceLeft错了吗?

是的,您想拥有fold而不是reduce的行为。 reduce生成的类型与集合的类型参数相同 - 它是fold,可以生成另一种类型。

scala> Seq("a","b","cd").reduceLeft(_+_)
res24: String = abcd

这里,Seq的类型参数是String - 因此reduceLeft也生成一个String。

scala> Seq("a","b","cd").foldLeft(0)(_+_.length)
res25: Int = 4

相比之下,foldLeft可以生成另一种类型 - 在本例中为Int。

在您的示例中seq.max是您想要的。尝试自己实现它,然后在查看源代码时验证您的实现是否正确。

提示:reducefold,其实现方式如下:

def reduce(f: (A, A) => A) =
  tail.fold(head)(f)

这就是reduce在调用空集合时抛出异常的原因。

答案 1 :(得分:3)

是的,你是。 reduceLeft必须返回与集合中的对象类型兼容的对象 - 在本例中为String。请参阅Programming in Scala以了解完全您的问题 - 直到相同的变量名称。

你想:

val longestLine 
  = lines.reduceLeft( (a,b) => if(a.length > b.length) a else b ).length

当然,这仅在集合非空时才有效。出于这个原因,和其他人一样,foldLeft通常更可取,如@Antoras所示。