1

私は私が完全に説明することができない結果でいくつかのテストを持っています。

最初のテストでは、4つの要素を含むリストでフィルター、マップ、およびリデュースを実行します。

{
    val counter = new AtomicInteger(0)
    val l = List(1, 2, 3, 4)
    val filtered = l.filter{ i =>
        counter.incrementAndGet()
        true
    }
    val mapped = filtered.map{ i =>
        counter.incrementAndGet()
        i*2
    }
    val reduced = mapped.reduce{ (a, b) =>
        counter.incrementAndGet()
        a+b
    }
    println("counted " + counter.get + " and result is " + reduced)
    assert(20 == reduced)
    assert(11 == counter.get)
}

カウンターは、予想どおり11倍に増分されます。フィルタリング中に要素ごとに1回、マッピング中に要素ごとに1回、4つの要素を合計するために3回です。

ワイルドカードを使用すると、結果が変わります。

{
    val counter = new AtomicInteger(0)
    val l = List(1, 2, 3, 4)
    val filtered = l.filter{
        counter.incrementAndGet()
        _ > 0
    }
    val mapped = filtered.map{
        counter.incrementAndGet()
        _*2
    }
    val reduced = mapped.reduce{ (a, b) =>
        counter.incrementAndGet()
        a+b
    }
    println("counted " + counter.get + " and result is " + reduced)
    assert(20 == reduced)
    assert(5 == counter.get)
}

リデュースでワイルドカードを使用する方法がわかりません(コードはコンパイルされません)が、現在、カウンターは5倍しかインクリメントされていません!!

それで、質問#1:なぜワイルドカードはカウンターが呼び出される回数を変更するのですか?それはどのように機能しますか?

次に、2番目の関連する質問です。ビューについての私の理解は、それらがモナディックメソッドに渡された関数を怠惰に実行するということでしたが、次のコードはそれを示していません。

{
    val counter = new AtomicInteger(0)
    val l = Seq(1, 2, 3, 4).view
    val filtered = l.filter{
        counter.incrementAndGet()
        _ > 0
    }
println("after filter: " + counter.get)
    val mapped = filtered.map{
        counter.incrementAndGet()
        _*2
    }
println("after map: " + counter.get)
    val reduced = mapped.reduce{ (a, b) =>
        counter.incrementAndGet()
        a+b
    }
println("after reduce: " + counter.get)
    println("counted " + counter.get + " and result is " + reduced)
    assert(20 == reduced)
    assert(5 == counter.get)
}

出力は次のとおりです。

after filter: 1
after map: 2
after reduce: 5
counted 5 and result is 20

質問2:関数がすぐに実行されるのはなぜですか?

Scala2.10を使用しています

4

1 に答える 1

11

あなたはおそらくそれを考えている

filter {
  println
  _ > 0
}

意味

filter{ i =>
  println
  i > 0
}

しかし、Scalaには他のアイデアがあります。その理由は

{ println; _ > 0 }

最初に何かを出力し、次に関数を返すステートメントです> 0。したがって、これは、実行していることを、関数を指定するための面白い方法として解釈します。これは、次のようになります。

val p = { println; (i: Int) => i > 0 }
filter(p)

これは次のようになります

println
val temp = (i: Int) => i > 0   // Temporary name, forget we did this!
val p = temp
filter(p)

ご想像のとおり、これは希望どおりに機能しません。最初に1回だけ印刷(または場合によっては増分)します。どちらの問題もこれに起因します。

「パラメータを入力する」という意味でアンダースコアを使用している場合は、式が1つしかないことを確認してください。複数のステートメントを使用している場合は、明示的に名前が付けられたパラメーターに固執するのが最善です。

于 2013-03-20T21:43:31.063 に答える