0

我正在研究99 个 Scala 问题以了解更多 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。

4

3 回答 3

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”,我怀疑编译器不能完全确定什么是什么的参数。

于 2012-07-16T18:22:15.657 回答
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>). 也许你刚刚注意到这里第一个括号之间的符号被交换了——这是因为每个以冒号结尾的方法都是右关联的而不是左关联的(进一步解释)。

现在我想给你一些进一步重构的提示:

  • Tuple2[A, B]可以写成(A, B)
  • 您不必编写所有类型。其中一些可以 - 并且应该 - 留下来清理你的代码(我知道你是一个初学者并且想写这个。只是作为一个提示......)。但不要离开
  • 列表大多被命名为xsys,因为这意味着“很多 x”或“很多 y”。这不是很重要但很常见
  • 您可以对参数进行模式匹配以将它们提取为易于阅读的名称:... { case (a, (b,c)) => ...}
  • 您的代码在声明任务时不起作用。你需要类似的东西List.fill(<n>)(<elem>)
  • 不要将元素附加到列表中,这是O(n). :::隐含地是一个追加操作 - 查看源代码
  • 对于这个任务foldLeft来说不是最好的解决方案。foldRight或者同义词:\可能更有效,因为该:::操作需要更少的元素来复制。但我更喜欢flatMap(见下文),这是一个map+flatten
    • 您可以使用 for-comprehension 来解决这个问题,这通常很容易阅读。有关如何在内部实现理解的更多信息,请参阅此内容。

总而言之,示例解决方案:

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")
}
于 2012-07-16T21:14:35.637 回答
1

foldLeft如果您通过 using调用显式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)}

查看这个问题的第一个答案,以获得对 Scala 调用语法的非常详细的解释,该语法也涵盖了您的情况。

于 2012-07-16T18:27:02.347 回答