Ich bin sehr neu in Scala, also vergib meine Unwissenheit! Ich versuche, Paare von Ganzzahlen zu durchlaufen, die durch ein Maximum begrenzt sind. Wenn beispielsweise die maximale 5 ist, dann sollte die Iteration zurück:Tail-rekursive begrenzte Strom von Paaren von ganzen Zahlen (Scala)?
(0, 0), (0, 1), ..., (0, 5), (1, 0), ..., (5, 5)
habe ich gewählt, um zu versuchen und Schwanz-rekursiv geben diese als Stream:
@tailrec
def _pairs(i: Int, j: Int, maximum: Int): Stream[(Int, Int)] = {
if (i == maximum && j == maximum) Stream.empty
else if (j == maximum) (i, j) #:: _pairs(i + 1, 0, maximum)
else (i, j) #:: _pairs(i, j + 1, maximum)
}
Ohne die tailrec Anmerkung der Code funktioniert:
scala> _pairs(0, 0, 5).take(11)
res16: scala.collection.immutable.Stream[(Int, Int)] = Stream((0,0), ?)
scala> _pairs(0, 0, 5).take(11).toList
res17: List[(Int, Int)] = List((0,0), (0,1), (0,2), (0,3), (0,4), (0,5), (1,0), (1,1), (1,2), (1,3), (1,4))
Aber das ist nicht gut genug für mich. Der Compiler wird unter Hinweis darauf, richtig, dass die letzte Zeile von _pairs ist _pairs nicht zurückkehren:
could not optimize @tailrec annotated method _pairs: it contains a recursive call not in tail position
else (i, j) #:: _pairs(i, j + 1, maximum)
^
Also, ich einige Fragen:
- direkt die Umsetzung über Adressierung, wie funktioniert ein Schwanz-rekursiv Rückkehr Stream [(Int, Int)]?
- einen Schritt zurück, was ist die speichereffizienteste Möglichkeit, über begrenzte Folgen von ganzen Zahlen zu iterieren? Ich möchte nicht über Range iterieren, weil Range extends IndexedSeq, und ich möchte nicht, dass die Sequenz vollständig im Speicher vorhanden ist. Oder liege ich falsch? Wenn ich über Range.view iteriere, vermeide ich, dass es in den Speicher kommt? (!)
In Python, alles was ich will:
In [6]: def _pairs(maximum):
...: for i in xrange(maximum+1):
...: for j in xrange(maximum+1):
...: yield (i, j)
...:
In [7]: p = _pairs(5)
In [8]: [p.next() for i in xrange(11)]
Out[8]:
[(0, 0),
(0, 1),
(0, 2),
(0, 3),
(0, 4),
(0, 5),
(1, 0),
(1, 1),
(1, 2),
(1, 3),
(1, 4)]
Vielen Dank für Ihre Hilfe! Wenn Sie denken, dass ich Referenzen/API-Dokumente/irgendetwas anderes lesen muss, sagen Sie mir bitte, weil ich daran interessiert bin zu lernen.
Vielen Dank für Ihre Antwort! Ich verstehe, warum das, was ich gemacht habe, nicht rekursiv ist, und ich würde definitiv 'for' verwenden. Das Problem, das ich habe, ist, dass "Paare", wie Sie vorgeschlagen haben, "IndexedSeq" zurückgibt. Daher wird das ganze Ergebnis im Speicher existieren, wenn "Paare" aufgerufen wird. Könnten Sie bitte erläutern, wie Sie Ansichten verwenden können, um dies zu vermeiden? –
Und haben Sie mehr Details und Referenzen über Streams und Thunks? Ich bin sehr neugierig darauf, wie ich den Stack nicht blasen werde, indem ich rekursiv eine nicht-Tail-Call optimierte Funktion aufruft, bei der ich keine Coroutinen verwende. So viel zu lernen! –
@AsimIhsan: Ich beantworte diese Fragen in einer Bearbeitung. –