Soweit ich das beurteilen kann, ist die collect
Funktion tatsächlich tail-rekursiv. Der erste Fall gibt eindeutig die acc
zurück. Der zweite Fall ruft zuerst FindSourceFilesForTarget
auf, ruft dann Set.union
auf und kehrt dann zurück. Man könnte es wie folgt umschreiben (das den Schwanz Rekursion deutlicher zeigt):
| hr::tl ->
let sources = FindSourceFilesForTarget hr
let acc = Set.union acc sources
collect tl
Da dies nur eine einzige Funktion selbst Aufruf ist, der Compiler es in eine Schleife optimiert. Dies ist, wie der kompilierte Code aussieht (wenn Sie Reflektor verwenden, um C# drehen):
public static FSharpSet<int> collect(FSharpList<int> t, FSharpSet<int> acc) {
while (true) {
FSharpList<int> fSharpList = t;
if (fSharpList.TailOrNull == null) break;
// The following corresponds to the second case
FSharpList<int> tl = fSharpList.TailOrNull;
int hr = fSharpList.HeadOrDefault;
// Variables 'acc' and 't' are mutated (instead of calling the function)
acc = SetModule.Union<int>(acc, Program.FindSourceFilesForTarget<int>(hr));
t = tl;
}
return acc;
}
Auf einer leicht in keinem Zusammenhang zur Kenntnis, man könnte auch dies mit Standard-Bibliothek Funktionen ausdrücken:
t |> Seq.map FindSourceFilesForTarget |> Set.unionMany
Sind Sie im Freigabemodus kompilieren? Tail-Aufrufe sind nicht optimiert, es sei denn, Sie befinden sich im Freigabemodus. – mydogisbox