Ich habe lange gegoogelt und kann immer noch keine Antwort finden. Von dem, was ich verstehe, verwendet F # 3.0, das auf .NET 4.5 ausgeführt wird, keine Tail-Rekursion für eine rekursive Methode, wenn der Aufrufer den Aufruf in einen try / catch- und / oder try / finally-Block gehüllt hat. Wie ist die Situation, wenn es einen Versuch gibt / fangen oder versuchen / schließlich ein paar Stufen den Stapel hinauf?
Wenn Sie den Rumpf einer rekursiven Funktion (Tail) in einem try
... with
Block umbrechen, ist die Funktion nicht mehr tail rekursiv, da der Aufrufrahmen während des rekursiven Aufrufs nicht verworfen werden kann mit einem registrierten Ausnahmebehandler im Stack zu bleiben.
Nehmen wir beispielsweise an, Sie haben so etwas wie iter
function für List
:
Wenn Sie iter f [1;2;3]
aufrufen, erstellt es 4 verschachtelte Stack-Frames mit Ausnahme-Handlern (und wenn Sie rethrow
in den Zweig with
hinzugefügt haben, würde die Fehlermeldung tatsächlich 4-mal ausgegeben).
Sie können Exception-Handler nicht wirklich hinzufügen, ohne die Tail-Rekursion zu unterbrechen. Normalerweise benötigen Sie jedoch verschachtelte Ausnahmehandler nicht. Die beste Lösung besteht also darin, die Funktion so umzuschreiben, dass sie bei jedem rekursiven Aufruf keine Ausnahmen behandeln muss:
%Vor% Dies hat eine etwas andere Bedeutung - aber es werden keine verschachtelten Exception-Handler erzeugt und loop
kann immer noch vollständig rekursiv sein.
Eine weitere Option wäre das Hinzufügen der Ausnahmebehandlung nur für den Rumpf , ausgenommen für den tailrekursiven Aufruf. Realistisch gesehen ist das einzige, was in diesem Beispiel eine Ausnahme auslösen kann, der Aufruf von f
;
Tags und Links .net f# tail-recursion