Ihre Beschreibung Ihres Algorithmus ist zu vage, um sie an dieser Stelle zu bewerten. Aber hier sind einige Dinge zu beachten.
CPS
Tatsächlich gibt es eine Möglichkeit, jeden Code in ein Formular umzuwandeln , das nur Tail-Calls verwendet. Dies ist die CPS-Transformation. CPS ( Continuation-Passing Style ) ist eine Form, Code auszudrücken, indem jeder Funktion eine Fortsetzung übergeben wird. Eine Fortsetzung ist ein abstrakter Begriff, der "den Rest einer Berechnung" darstellt. In Code in CPS Form ausgedrückt, die auf natürliche Weise reify eine Fortsetzung ist als eine Funktion , die einen Wert annimmt. In CPS wird statt einer Funktion, die einen Wert zurückgibt, die Funktion angewendet, die die aktuelle Fortsetzung darstellt, um von der Funktion "zurückgegeben" zu werden.
Betrachten Sie beispielsweise die folgende Funktion:
(lambda (a b c d)
(+ (- a b) (* c d)))
Dies könnte in CPS wie folgt ausgedrückt werden:
(lambda (k a b c d)
(- (lambda (v1)
(* (lambda (v2)
(+ k v1 v2))
a b))
c d))
Es ist hässlich und oft langsam, hat aber einige Vorteile:
- Die Transformation kann vollständig automatisiert werden. Sie müssen den Code also nicht in CPS-Form schreiben (oder anzeigen).
- In Kombination mit Thunking und Trampolining kann die Tail-Call-Optimierung in Sprachen durchgeführt werden, die keine Tail-Call-Optimierung bieten. (Die Optimierung von direkt rekursiven Funktionen für den Endanruf kann auch auf andere Weise erfolgen, z. B. durch Konvertieren des rekursiven Aufrufs in eine Schleife. Indirekte Rekursion ist jedoch auf diese Weise nicht so einfach zu konvertieren.)
- Mit CPS werden Fortsetzungen zu erstklassigen Objekten. Da Fortsetzungen das Wesentliche der Steuerung sind, kann praktisch jeder Steuerungsoperator als Bibliothek implementiert werden, ohne dass eine spezielle Unterstützung durch die Sprache erforderlich ist. Zum Beispiel können Goto, Ausnahmen und kooperatives Threading mithilfe von Fortsetzungen modelliert werden.
TCO
Es scheint mir, dass der einzige Grund, sich mit Tail-Recursion (oder Tail-Calls im Allgemeinen) zu befassen, die Tail-Call-Optimierung (TCO) ist. Ich denke also, eine bessere Frage zu stellen ist: "Ist mein Transformationsertragcode für Tail-Calls optimierbar?".
Wenn wir noch einmal CPS betrachten, ist eine seiner Eigenschaften, dass der in CPS ausgedrückte Code nur aus Tail-Calls besteht. Da es sich bei allem um einen Tail-Call handelt, müssen wir keinen Rücksprungpunkt auf dem Stack speichern. Also alle Code in CPS Form muss Tail-Call - optimiert sein, nicht wahr?
Nicht ganz. Sie sehen, obwohl es den Anschein hat, als hätten wir den Stapel entfernt, haben wir lediglich die Art und Weise geändert, wie wir ihn darstellen. Der Stapel ist nun Teil des Verschlusses, der eine Fortsetzung darstellt. CPS optimiert also nicht auf magische Weise alle unsere Code-Tail-Calls.
Also, wenn CPS nicht alle TCO machen kann, gibt es eine Transformation speziell für die direkte Rekursion, die das kann? Nein, im Allgemeinen nicht. Einige Rekursionen sind linear, andere nicht. Nichtlineare (z. B. Baum-) Rekursionen müssen einfach irgendwo eine variable Zustandsgröße beibehalten.