我正在通过Ninety-Nine Scala Problems了解更多Scala。我在P12上并为此问题编写了以下解决方案。
def decode(l : List[Tuple2[Int,Symbol]]) : List[Symbol]
= l foldLeft(List[Symbol]()) { (symbols:List[Symbol], e:Tuple2[Int, Symbol]) => symbols ::: List(e._2) }
我收到以下编译错误。
error: type mismatch;
found : (List[Symbol], (Int, Symbol)) => List[Symbol]
required: Int
= l foldLeft(List[Symbol]()) { (symbols:List[Symbol], e:
Tuple2[Int, Symbol]) => symbols ::: List(e._2) }
导致编译错误的原因是什么?
Scala版本:Scala代码运行版版本2.10.0-M3 - 版权所有2002-2011,LAMP / EPFL。
答案 0 :(得分:4)
看起来你正在使用中缀foldLeft调用,你只需将其更改为:
def decode(l : List[Tuple2[Int,Symbol]]) : List[Symbol]
= l.foldLeft(List[Symbol]()) { (symbols:List[Symbol], e:Tuple2[Int, Symbol]) => symbols ::: List(e._2) }
注意“l.foldLeft”而不是“l foldLeft”,我怀疑编译器无法确定什么是参数。
答案 1 :(得分:3)
已经给出了解决方案,但我认为需要更多解释:
如果表达式位于操作员位置,则只允许留下括号和圆点。如果表达式具有<object> <method> <param>
形式,则表达式位于运算符位置。对于包含多个显式参数列表foldLeft
的方法,情况并非如此。因此,你必须写<list>.foldLeft(<init>)(<function>)
。然而,Scala有一个特殊的规则可以解决这个问题 - 您可以插入另一组括号:(<list> foldLeft <init>) (<function>)
。此外,还有另一种称为/:
的方法,它是foldLeft
的同义词,定义为def /:[B](z: B)(op: (B, A) => B): B = foldLeft(z)(op)
。它允许您编写(<init> /: <list>) (<function>)
。也许你刚才注意到第一个括号之间的符号是交换的 - 这是因为每个以冒号结尾的方法都是正确的 - 而不是左关联(further explanation)。
现在我想给你一些进一步重构的提示:
Tuple2[A, B]
可以写成(A, B)
xs
或ys
,因为这意味着“很多x”或“很多y”。这不是很重要但很常见... { case (a, (b,c)) => ...}
List.fill(<n>)(<elem>)
O(n)
。隐式地:::
是追加操作 - 请查看sources。foldLeft
不是最佳解决方案。 foldRight
或同义词:\
可能更有效,因为:::
操作需要较少的元素进行复制。但我更喜欢flatMap
(见下文),这是map+flatten
所有示例解决方案中都包含:
object Test extends App {
def decode1(l: List[Tuple2[Int, Symbol]]): List[Symbol] =
l.foldLeft(List[Symbol]()) { (symbols: List[Symbol], e: Tuple2[Int, Symbol]) => symbols ::: List.fill(e._1)(e._2) }
def decode2(xs: List[(Int, Symbol)]): List[Symbol] =
(xs foldLeft List.empty[Symbol]) { case (xs, (n, s)) => xs ::: List.fill(n)(s) }
def decode3(xs: List[(Int, Symbol)]): List[Symbol] =
(xs foldRight List.empty[Symbol]) { case ((n, s), xs) => List.fill(n)(s) ::: xs }
def decode4(xs: List[(Int, Symbol)]): List[Symbol] =
(List.empty[Symbol] /: xs) { case (xs, (n, s)) => xs ::: List.fill(n)(s) }
def decode5(xs: List[(Int, Symbol)]): List[Symbol] =
xs flatMap { case (n, s) => List.fill(n)(s) }
def decode6(xs: List[(Int, Symbol)]): List[Symbol] =
for {
(n, s) <- xs
ys <- List.fill(n)(s)
} yield ys
val xs = List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e))
val ys = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)
println("start testing")
val tests = List[List[(Int, Symbol)] => List[Symbol]](decode1, decode2, decode3, decode4, decode5, decode6)
for (t <- tests)
assert(t(xs) == ys)
println("finished")
}
答案 2 :(得分:1)
如果您使用foldLeft
明确调用l.foldLeft
,则错误消失:
def decode(l: List[Tuple2[Int,Symbol]]): List[Symbol] =
l.foldLeft(List[Symbol]()){(symbols:List[Symbol], e:Tuple2[Int, Symbol]) =>
symbols ::: List(e._2)}
查看this question的第一个答案,详细解释Scala的调用语法,该语法也涵盖了您的案例。