0

Scalaをもっと学ぶために、99の 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 -- Copyright 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) }

「lfoldLeft」ではなく「l.foldLeft」に注意してください。コンパイラーは、何が何のパラメーターであるかを完全に判別できないと思われます。

于 2012-07-16T18:22:15.657 に答える
3

解決策はすでに示されていますが、さらに説明が必要だと思います。

式が演算子の位置にある場合にのみ、括弧とドットを残すことができます。式が の場合、式は演算子の位置にあり<object> <method> <param>ます。これは、複数の明示的なパラメーター リストを含むメソッドの場合には当てはまりませんfoldLeft。したがって、書く必要があります<list>.foldLeft(<init>)(<function>)。それにもかかわらず、Scala にはこれを回避するための特別なルールがあります。別の括弧のセットを挿入できます: (<list> foldLeft <init>) (<function>). さらに、 と定義され/:た と同義であると呼ばれる別のメソッドがあります。それはあなたが書くことを可能にします。ここで、最初の括弧の間の記号が入れ替わっていることに気付いたかもしれません。これは、コロンで終わる各メソッドが左結合ではなく右結合であるという規則によるものです (詳細説明)。foldLeftdef /:[B](z: B)(op: (B, A) => B): B = foldLeft(z)(op)(<init> /: <list>) (<function>)

ここで、さらにリファクタリングするためのヒントをいくつか提供したいと思います。

  • Tuple2[A, B]次のように書くことができます(A, B)
  • すべてのタイプを記述する必要はありません。それらのいくつかは、コードを整理するために残しておくことができます (また、残しておく必要があります) (あなたが初心者で、これを書きたいと思っていることはわかっています。ヒントとしてのみ...)。でも離れないで
  • xsリストはたいていorのような名前が付けられysますが、これは「たくさんの x」または「たくさんの y」を意味するためです。これはあまり重要ではありませんが、一般的です
  • パラメータをパタリングして、読みやすい名前に抽出できます。... { case (a, (b,c)) => ...}
  • タスクを要求しているため、コードは機能しません。次のようなものが必要ですList.fill(<n>)(<elem>)
  • リストに要素を追加しないでください。これはO(n). :::暗黙的に追加操作です -ソースを見てください。
  • このタスクfoldLeftは、思いつく最善の解決策ではありません。または、操作でコピーする必要のある要素が少ないためfoldRight、シノニムの:\方が効率的である可能性があります。:::しかし、私はflatMap(以下を参照)、map+flatten
    • for-comprehension を使用してこれを解決できます。これは多くの場合、読みやすいでしょう。for-comprehensions が内部でどのように実現されるかについての詳細は、これを参照してください。

すべてのサンプルソリューションのすべて:

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を使用して明示的に呼び出すと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 に答える