Scala在处理元组列表时出现了令人困惑的编译时错误

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

我正在努力学习更多的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;
 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”案例)。非常感谢你的解释。同时,感谢你的宝贵提示和提示:)