從其他答案一種不同的方法是使用尾遞歸。
例如,尾遞歸的好處是什麼?
[1..int CoffeMachine.Lifetime] |> List.iter (printf "%i")
或者:
for i = 1 to int CoffeMachine.Lifetime do
printf "%i" i
從性能和內存的角度List.iter
比差了for loop
,因爲第一個創建一個單鏈表(F#不可改變的名單是引擎蓋下單鏈表)和迭代超過它。在許多情況下,增加的CPU和內存使用量並不相關,但在其他情況下是這樣。
像Seq
這樣的懶惰集合可以緩解這種情況,但不幸的是Seq
目前在F#中效率不高。 Nessos Streams將是更好的選擇。
F#中for loop
的問題在於它不能過早地被破壞(break
或continue
在F#中不存在)。
此外,當彙總結果時,for loop
模式通常會迫使我們進入可變變量模式。
尾遞歸允許我們聚合結果而不依賴於可變變量並支持中止。此外,尾遞歸循環可以返回值for loop
不能(表達式結果總是unit
)
F#中的尾遞歸也是有效的,因爲F#檢測尾遞歸函數並將其展開到引擎蓋下的循環中。
這是上面的代碼如何尾遞歸循環可能看起來像:
let rec loop i l = if i <= l then printf "%i" i; loop (i + 1) l
loop 1 (int CoffeMachine.Lifetime)
使用ILSpy
一個看到這個被編譯成一個while循環:
internal static void [email protected](int i, int l)
{
while (i <= l)
{
PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit> format = new PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit, int>("%i");
PrintfModule.PrintFormatToTextWriter<FSharpFunc<int, Unit>>(Console.Out, format).Invoke(i);
int arg_28_0 = i + 1;
l = l;
i = arg_28_0;
}
}
這取決於如何壽命將在生產代碼產生,但使用' int'函數可能不是一個好主意。從DB或其他意想不到的計算或檢索可能會導致3.9 ...而不是4.0,然後使用'int'後,你將有3年而不是4年。也許你應該用'round'來代替。 –