Ich weiß, dies ist gegen den üblichen Sinn von SO-Fragen, aber der folgende Code funktioniert, obwohl ich denke, dass es nicht funktionieren sollte. Unten ist ein kleines Scala-Programm, das Fortsetzungen mit einer while-Schleife verwendet. Nach meinem Verständnis der Art der Fortsetzungsübergabe sollte dieser Code einen Stack-Überlauffehler erzeugen, indem für jede Iteration der while-Schleife ein Frame zum Stack hinzugefügt wird. Es funktioniert jedoch gut.Verwendung von Scala-Fortsetzungen mit While-Schleifen
import util.continuations.{shift, reset}
class InfiniteCounter extends Iterator[Int] {
var count = 0
var callback: Unit=>Unit = null
reset {
while (true) {
shift {f: (Unit=>Unit) =>
callback = f
}
count += 1
}
}
def hasNext: Boolean = true
def next(): Int = {
callback()
count
}
}
object Experiment3 {
def main(args: Array[String]) {
val counter = new InfiniteCounter()
println(counter.next())
println("Hello")
println(counter.next())
for (i <- 0 until 100000000) {
counter.next()
}
println(counter.next())
}
}
Die Ausgabe lautet:
1
Hello
2
100000003
Meine Frage ist: Warum gibt es keinen Stack-Überlauf? Tut der Scala-Compiler die Tail-Call-Optimierung (was ich nicht mit Fortsetzungen machen konnte) oder gibt es noch etwas anderes?
(Dieses Experiment ist auf Github zusammen mit der sbt Konfiguration ist es erforderlich laufen. https://github.com/jcrudy/scala-continuation-experiments Siehe commit 7cec9befcf58820b925bb222bc25f2a48cbec4a6)
Ich denke, das ist eine großartige Erklärung für etwas, das ziemlich verwirrend ist. Ich werde versuchen, dies visuell zu skizzieren, und ich werde hier einen Link veröffentlichen, wenn ich etwas Illustratives erstelle. Um das klarzustellen, bedeutet dies, dass diese Konstruktion nicht nur den Stack nicht durchbrennen wird, sondern der Gesamtspeicherbedarf auch bescheiden ist und nicht von der Anzahl der "Iterationen" abhängt? – jcrudy
@jcrudy - Ja, die Speicheranforderung ist unabhängig von der Anzahl der Iterationen im 'for' Ausdruck. Als einfachen Test habe ich deinen Code wie folgt ausgeführt: 'JAVA_OPTS =" - Xmx2M -verbose: gc "scala Experiment3' (das funktioniert auf meinem Laptop). Dies beweist, dass die 100M-Iterationen mit nur 2 MB Heap-Speicherplatz arbeiten. Wenn Sie die Option für ausführliche Garbage Collection hinzufügen, können Sie auch sehen, dass die tatsächliche Speicherbelegung während der gesamten Ausführung ziemlich konstant bleibt. – DaoWen
Es gibt einen schönen, illustrierten Blogbeitrag von Rich Dougherty auf Trampolinen in Scala: http://blog.richdougherty.com/2009/04/tail-calls-tailrec-and-trampolines.html – jcrudy