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!