Scala在处理元组列表时出现了令人困惑的编译时错误
我正在努力学习更多的Scala。我在第12页,为这个问题编写了下面的解决方案Scala在处理元组列表时出现了令人困惑的编译时错误,scala,functional-programming,Scala,Functional Programming,我正在努力学习更多的Scala。我在第12页,为这个问题编写了下面的解决方案 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
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 code runner版本2.10.0-M3——版权所有2002-2011,LAMP/EPFL。看起来这是您对中缀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”,我怀疑编译器不能完全确定what的参数是什么。如果使用
l.foldLeft
调用explicit,则错误消失:
def decode(l: List[Tuple2[Int,Symbol]]): List[Symbol] =
l.foldLeft(List[Symbol]()){(symbols:List[Symbol], e:Tuple2[Int, Symbol]) =>
symbols ::: List(e._2)}
请参阅to的第一个答案,以获得有关Scala调用语法的非常详细的解释,该语法也涵盖了您的案例。解决方案已经给出,但我认为需要更多的解释:
如果表达式处于运算符位置,则只允许保留括号和点。如果表达式的形式为
,则表达式处于运算符位置。对于包含多个显式参数列表(如foldLeft
)的方法,情况并非如此。因此,您必须编写.foldLeft()()
。然而Scala有一个特殊的规则来解决这个问题——您可以插入另一组括号:(foldLeft)(
)。此外,还有另一种称为/:
的方法,它是foldLeft
的同义词,定义为def/:[B](z:B)(op:(B,a)=>B):B=foldLeft(z)(op)
。它允许您编写(/:)()
。也许您刚刚注意到,第一个括号之间的符号是交换的——这是因为每个以冒号结尾的方法都是右键,而不是左键()
现在我想给你一些关于进一步重构的提示:
Tuple2[A,B]
可以写成(A,B)
- 你不必写所有的类型。其中一些可以——也应该——被留下来清理你的代码(我知道你是一个初学者,想写这篇文章。只是作为一个提示…)。但是不要离开
- 列表的名称大多类似于
xs
或ys
,因为这意味着“大量的x”或“大量的y”。这不是很重要,但很常见
- 您可以对参数进行模式匹配,将其提取为易于阅读的名称:
。。。{案例(a,(b,c))=>…}
- 您的代码在声明任务时不起作用。您需要类似于
List.fill()()
- 不要将元素附加到列表中,这是
O(n)
:
隐式地是一个追加操作-请查看
- 对于这项任务,
foldLeft
并不是最好的解决方案foldRight
或同义词:\
可能更有效,因为:
操作需要复制的元素更少。但是我更喜欢flatMap
(见下文),它是map+flatte
- 你可以用一种理解的方法来解决这个问题,这通常很容易阅读。有关如何在内部实现理解的更多信息,请参阅
在所有示例解决方案中:
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")
}
对象测试扩展应用程序{
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]=
为了{
(n,s)谢谢肖恩的回答。关于这一点,有什么好的文档、链接、博客帖子等吗?这里已经有一些关于这一点的条目:我想说,经验法则是只有在有明确理由的情况下才这样做(如“4+4”案例)。非常感谢你的解释。同时,感谢你的宝贵提示和提示:)