F# 程式設計/控制流
| F# : 控制流 |
在所有程式語言中,控制流指的是程式碼中做出的決策,這些決策影響了應用程式中語句執行的順序。F# 的命令式控制流元素與其他語言中遇到的類似。
大多數來自 C#、Java 或 C++ 背景的程式設計師熟悉指令式程式設計風格,這種風格在應用程式中使用迴圈、可變資料和帶有副作用的函式。雖然 F# 主要鼓勵使用函數語言程式設計風格,但它也具有允許程式設計師以更命令式風格編寫程式碼的結構。在以下情況下,指令式程式設計很有用
- 與 .NET Framework 中的大多數物件互動,這些物件本質上都是命令式的。
- 與高度依賴副作用的元件互動,例如 GUI、I/O 和套接字。
- 程式碼片段的指令碼編寫和原型設計。
- 初始化複雜的資料結構。
- 最佳化命令式版本的演算法比函式式版本更高效的程式碼塊。
F# 的 if/then/elif/else 結構在本手冊前面已經介紹過,為了更正式地介紹它,if/then 結構有以下語法
(* simple if *)
if expr then
expr
(* binary if *)
if expr then
expr
else
expr
(* multiple else branches *)
if expr then
expr
elif expr then
expr
elif expr then
expr
...
else
expr
與所有 F# 程式碼塊一樣,if 語句的範圍擴充套件到在其下方縮排的任何程式碼。例如
open System
let printMessage condition =
if condition then
printfn "condition = true: inside the 'if'"
printfn "outside the 'if' block"
let main() =
printMessage true
printfn "--------"
printMessage false
Console.ReadKey(true) |> ignore
main()
此程式輸出
condition = true: inside the 'if' outside the 'if' block -------- outside the 'if' block
F# 有三個布林運算子
| 符號 | 描述 | 示例 |
|---|---|---|
&&
|
邏輯與(中綴,短路) | true && false (* returns false *)
|
||
|
邏輯或(中綴,短路) | true || false (* returns true *)
|
not
|
邏輯非 | not false (* returns true *)
|
&& 和 || 運算子是短路的,這意味著 CLR 將執行最少的評估以確定條件是否成功或失敗。例如,如果 && 左側評估為 false,則無需評估右側;類似地,如果 || 左側評估為 true,則無需評估表示式的右側。
下面是 F# 中短路演示
open System
let alwaysTrue() =
printfn "Always true"
true
let alwaysFalse() =
printfn "Always false"
false
let main() =
let testCases =
["alwaysTrue && alwaysFalse", fun() -> alwaysTrue() && alwaysFalse();
"alwaysFalse && alwaysTrue", fun() -> alwaysFalse() && alwaysTrue();
"alwaysTrue || alwaysFalse", fun() -> alwaysTrue() || alwaysFalse();
"alwaysFalse || alwaysTrue", fun() -> alwaysFalse() || alwaysTrue();]
testCases |> List.iter (fun (msg, res) ->
printfn "%s: %b" msg (res())
printfn "-------")
Console.ReadKey(true) |> ignore
main()
alwaysTrue 和 alwaysFalse 方法分別返回 true 和 false,但它們還會在每次評估函式時向控制檯列印一條訊息。
此程式輸出以下內容
Always true Always false alwaysTrue && alwaysFalse: false ------- Always false alwaysFalse && alwaysTrue: false ------- Always true alwaysTrue || alwaysFalse: true ------- Always false Always true alwaysFalse || alwaysTrue: true -------
如上所示,表示式 alwaysTrue && alwaysFalse 評估表示式的兩側。alwaysFalse && alwaysTrue 只評估表示式的左側;由於左側返回 false,因此無需評估右側。
for 迴圈傳統上用於遍歷定義明確的整數範圍。for 迴圈的語法定義如下
for var = start-expr to end-expr do
... // loop body
以下是一個簡單的程式,它打印出數字 1 到 10
let main() =
for i = 1 to 10 do
printfn "i: %i" i
main()
此程式輸出
i: 1 i: 2 i: 3 i: 4 i: 5 i: 6 i: 7 i: 8 i: 9 i: 10
此程式碼從使用者那裡獲取輸入來計算平均值
open System
let main() =
Console.WriteLine("This program averages numbers input by the user.")
Console.Write("How many numbers do you want to add? ")
let mutable sum = 0
let numbersToAdd = Console.ReadLine() |> int
for i = 1 to numbersToAdd do
Console.Write("Input #{0}: ", i)
let input = Console.ReadLine() |> int
sum <- sum + input
let average = sum / numbersToAdd
Console.WriteLine("Average: {0}", average)
main()
此程式輸出
This program averages numbers input by the user. How many numbers do you want to add? 3 Input #1: 100 Input #2: 90 Input #3: 50 Average: 80
使用以下語法遍歷專案集合通常很方便
for pattern in expr do
... // loop body
例如,我們可以使用 fsi 打印出購物清單
> let shoppingList =
["Tofu", 2, 1.99;
"Seitan", 2, 3.99;
"Tempeh", 3, 2.69;
"Rice milk", 1, 2.95;];;
val shoppingList : (string * int * float) list
> for (food, quantity, price) in shoppingList do
printfn "food: %s, quantity: %i, price: %g" food quantity price;;
food: Tofu, quantity: 2, price: 1.99
food: Seitan, quantity: 2, price: 3.99
food: Tempeh, quantity: 3, price: 2.69
food: Rice milk, quantity: 1, price: 2.95
顧名思義,while 迴圈會在特定條件為真時無限地重複執行程式碼塊。while 迴圈的語法定義如下
while expr do
... // loop body
當我們不知道要執行程式碼塊多少次時,我們會使用 while 迴圈。例如,假設我們希望使用者猜測秘密區域的密碼;使用者可能在第一次嘗試時就猜對了密碼,也可能嘗試數百萬個密碼,我們只是不知道。以下是一個簡短的程式,它要求使用者在最多 3 次嘗試中猜對密碼
open System
let main() =
let password = "monkey"
let mutable guess = String.Empty
let mutable attempts = 0
while password <> guess && attempts < 3 do
Console.Write("What's the password? ")
attempts <- attempts + 1
guess <- Console.ReadLine()
if password = guess then
Console.WriteLine("You got the password right!")
else
Console.WriteLine("You didn't guess the password")
Console.ReadKey(true) |> ignore
main()
此程式輸出以下內容
What's the password? kitty What's the password? monkey You got the password right!