Skip to main content

  | मौसम…

411 समाचार
Public archive edition · Attributed source reporting with original dates · AI drafts are excluded

411 REFERENCE · Wikibooks

F Sharp Programming/Control Flow

Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.

F Sharp Mutable Data Arrays Control Flow In all programming languages, control flow refers to the decisions made in code that affect the order in which statements are executed in an application. F#'s imperative control flow elements are similar to those encountered in other languages. Imperative Programming in a Nutshell Most programmers coming from a C#, Java, or C++ background are familiar with an imperative style of programming which uses loops, mutable data, and functions with side-effects in applications. While F# primarily encourages the use of a functional programming style, it has constructs which allow programmers to write code in a more imperative style as well. Imperative programming can be useful in the following situations: Interacting with many objects in the .NET Framework, most of which are inherently imperative. Interacting with components that depend heavily on side-effects, such as GUIs, I/O, and sockets. Scripting and prototyping snippets of code. Initializing complex data structures. Optimizing blocks of code where an imperative version of an algorithm is more efficient than the functional version. if/then Decisions F#'s if/then/elif/else construct has already been seen earlier in this book, but to introduce it more formally, the if/then construct has the following syntaxes: (* 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 Like all F# blocks, the scope of an if statement extends to any code indented under it. For example: 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() This program prints: condition = true: inside the 'if' outside the 'if' block -------- outside the 'if' block Working With Conditions F# has three boolean operators: Symbol Description Example && Logical AND (infix, short-circuited) true && false (* returns false *) || Logical OR (infix, short-circuited) true || false (* returns true *) not Logical NOT not false (* returns true *) The && and || operators are short-circuited, meaning the CLR will perform the minimum evaluation necessary to determine whether the condition will succeed or fail. For example, if the left side of an && evaluates to false, then there is no need to evaluate the right side; likewise, if the left side of a || evaluates to true, then there is no need to evaluate the right side of the expression. Here is a demonstration of short-circuiting in 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() The alwaysTrue and alwaysFalse methods return true and false respectively, but they also have a side-effect of printing a message to the console whenever the functions are evaluated. This program outputs the following: Always true Always false alwaysTrue && alwaysFalse: false ------- Always false alwaysFalse && alwaysTrue: false ------- Always true alwaysTrue || alwaysFalse: true ------- Always false Always true alwaysFalse || alwaysTrue: true ------- As you can see above, the expression alwaysTrue && alwaysFalse evaluates both sides of the expression. alwaysFalse && alwaysTrue only evaluates the left side of the expression; since the left side returns false, its unnecessary to evaluate the right side. for Loops Over Ranges for loops are traditionally used to iterate over a well-defined integer range. The syntax of a for loop is defined as: for var = start-expr to end-expr do ... // loop body Here's a trivial program which prints out the numbers 1 - 10: let main() = for i = 1 to 10 do printfn "i: %i" i main() This program outputs: i: 1 i: 2 i: 3 i: 4 i: 5 i: 6 i: 7 i: 8 i: 9 i: 10 This code takes input from the user to compute an average: 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 outputs: 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 Loops Over Collections and Sequences Its often convenient to iterate over collections of items using the syntax: for pattern in expr do ... // loop body For example, we can print out a shopping list in 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 Loops As the name suggests, while loops will repeat a block of code indefinitely while a particular condition is true. The syntax of a while loop is defined as follows: while expr do ... // loop body We use a while loop when we don't know how many times to execute a block of code. For example, lets say we wanted the user to guess a password to a secret area; the user could get the password right on the first try, or the user could try millions of passwords, we just don't know. Here is a short program that requires a user to guess a password correctly in at most 3 attempts: 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() This program outputs the following: What's the password? kitty What's the password? monkey You got the password right! F Sharp Mutable Data Arrays