[Scala] - for-comprehensions

0

Na oficjalnej stronie z dokumentacją (np: przykład 1.) znalazłem informację że pętla :

for(x <- c1; y <- c2; z <-c3) {...}

jest zamieniana pod powłoką na coś takiego :

c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))

Coś mi nie pasowało i przeprowadziłem eksperyment:

for(i <- 1 until 4; _ = println("i = " + i); j <- 1 until 3; _ = println("j = " + j)) {}

i = 1 i = 2 i = 3 j = 1 j = 2 j = 1 j = 2 j = 1 j = 2

(1 until 4).foreach(i => 
                    {println("i = " + i); (1 until 3).foreach(j => 
                                                              {println("j = " + j)})})

i = 1 j = 1 j = 2 i = 2 j = 1 j = 2 i = 3 j = 1 j = 2

Sposób działania obu metod jest różny czy czegoś nie rozumiem ?

0

Opcja desugar w IntelliJ (dostępna pod menu z Alt+Enter po tym jak się ustawi kursor na słowie kluczowym for) sugeruje, że w rzeczywistości zachodzi następująca transformacja:

(1 until 4).map(i => (println(s"i = $i"), i)).foreach { case (_, i) =>
  (1 until 3).map(j => (println(s"j = $j"), j)).foreach { case (_, j) =>
    {}
  }
}

W sumie trochę dziwne, ale może to tak działa z jakiegoś powodu.

Spróbuj zapytać o co chodzi na: https://users.scala-lang.org/

Aktualizacja: w podlinkowanej dokumentacji w example 4 jest pokazana bardzo podobna transformacja.

0

Ale czy to rozwiązuje problem ? Mi się wydaje że efekty byłby takie same jak w pierwszym poście.

0

Zauważ, że pierwszym krokiem jest (1 until 4).map(i => (println(s"i = $i"), i)). Mapowanie w tym przypadku jest zachłanne, więc najpierw przemapuje się cała kolekcja, a dopiero potem odpali się foreach.

0

Hmm, to jaki jest z tego wniosek ? Operacja map jest zachłanna a foreach nie ? Czy to zależy od użytego kontekstu ?

1

foreach jest zawsze zachłanny, ale nie robisz go w stylu a.foreach(b => c).foreach(d => e), bo foreach zwraca () na którym nie da się już odpalić kolejnego foreacha. Operacja map jest zachłanna dla kolekcji zachłannych (np List) i leniwa dla kolekcji leniwych (np Stream). Natomiast w przypadku, który tutaj omawiamy ważna jest kolejność operacji. Jest różnica między a.flatMap(b => c).map(d => e), a a.flatMap(b => c.map(d => e)). W pierwszym przypadku dla zachłannej kolekcji mapowanie b => c kończy się przed zaczęciem mapowania d => e. W drugim są one pomieszane.

0

To nadal czegoś nie rozumiem. Jak to się ma do różnych wyników z pierwszego posta ?

2

Tak, że niewłaściwie przetłumaczyłeś fora na sekwencję kombinatorów. Zapomniałeś o krokach .map(. Popatrz na przykład 4. z dokumentacji, którą sam podlinkowałeś. Tam jest pokazane jak są tłumaczone przypisania w forze.

0

Hej,
ciekawa sprawa... Generalnie ta druga sekwencja pracuje jak standardowa pętla podwójna, jej odpowiednik:

for(i <- 1 until 4; j <- 1 until 3) println("i = " + i, " j = " + j)}

Natomiast pierwsza sekwencja przelatuje (prawidłowo) całą pętlę podwójną nadając pierwszej iteracji priorytet... ciężko mi nawet znaleźć jakiś odpowiednik... :)

0

Witam!!!!! Czy Java zmieni te składnie na podobną do Pythona?

1 użytkowników online, w tym zalogowanych: 0, gości: 1