O ile mogę stwierdzić, funkcja collect
jest rzeczywiście rekursywna. Pierwszy przypadek po prostu zwraca wartość acc
. Drugi przypadek najpierw wywołuje FindSourceFilesForTarget
, a następnie wywołuje Set.union
, a następnie zwraca. Można go przepisać następująco (co pokazuje ogon-rekurencji jaśniej):
| hr::tl ->
let sources = FindSourceFilesForTarget hr
let acc = Set.union acc sources
collect tl
Ponieważ jest tylko jedna funkcja nazywająca siebie, kompilator optymalizuje go w pętli. W ten sposób skompilowany kod wygląda (przy użyciu reflektor, aby włączyć go do C#):
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;
}
na nieco niepowiązanych nuty, można również wyrazić to za pomocą standardowych funkcji biblioteki:
t |> Seq.map FindSourceFilesForTarget |> Set.unionMany
Czy jesteś kompilacja w trybie wydania? Ogonowe połączenia nie są optymalizowane, chyba że jesteś w trybie zwolnienia. – mydogisbox