某個事物能夠以自身來定義,這種能力稱為遞迴。在 F# 中,遞迴最常見於遞迴函式,也就是會呼叫自身的函式。
遞迴函式至少需要有一個_基本情況_,以及至少一個_遞迴情況_。_基本情況_會回傳一個值,而不會再次呼叫函式。_遞迴情況_則會再次呼叫函式,並修改輸入,讓它終究能符合基本情況。
遞迴函式的定義方式和一般函式相同,只是要加上rec修飾詞。少了這個修飾詞,函式就_無法_呼叫自身,任何嘗試這麼做都會導致編譯錯誤。因此,必須明確選擇使用遞迴。
let rec factorial x =
// Base case
if x = 1 then
1
// Recursive case
else
x * factorial (x - 1)
F# 也透過差別聯合型別支援遞迴型別。遞迴的差別聯合型別,其資料中會有一個或多個情況參照到這個差別聯合型別本身。和遞迴函式一樣,遞迴型別也必須有一個基本情況。和遞迴函式不同的是,遞迴型別不使用rec關鍵字。
type RussianDoll =
| Doll // Base case
| Layer of RussianDoll // Recursive case
在這項練習中,你會在一間提供外送服務的披薩店工作。
店裡提供 3 種披薩:
顧客也可以支付少許額外費用,選擇 2 個額外選項:
當顧客下訂單時,如果他們只訂 1 或 2 個披薩,就會加收額外費用:
你有 3 個任務,每個任務都會處理披薩和價格。
定義Pizza差別聯合,以代表披薩類型以及可以加到披薩上的 2 個額外選項:
MargheritaCapreseFormaggioExtraSauceExtraToppings實作pizzaPrice函式來計算披薩的價格:
pizzaPrice Caprese
// => 9
實作orderPrice函式來計算披薩訂單的價格:
orderPrice [Margherita; Formaggio]
// => 19