Skip to content
AgileLogics
5 min read

Loops

Prerequisites: Lists

F# has loops for when you want to do something repeatedly — print, write to a file, update a mutable value. To compute a new collection, prefer List.map, List.filter, and friends.

for ... in

for fruit in ["apple"; "banana"; "cherry"] do
    printfn "I like %s" fruit

for i in 1 .. 3 do
    printf "%d " i
printfn ""

for i in 10 .. -3 .. 1 do
    printf "%d " i
printfn ""

for (name, age) in [("Ada", 36); ("Alan", 41)] do
    printfn "%s is %d" name age
I like apple
I like banana
I like cherry
1 2 3
10 7 4 1
Ada is 36
Alan is 41

for ... in works with any sequence, a range (1 .. 3), or a range with a step (10 .. -3 .. 1), and can destructure tuples.

for ... to

for i = 1 to 3 do
    printf "%d " i
for i = 3 downto 1 do
    printf "%d " i
printfn ""
1 2 3 3 2 1

while

let mutable n = 27
let mutable steps = 0
while n <> 1 do
    n <- if n % 2 = 0 then n / 2 else 3 * n + 1
    steps <- steps + 1
printfn "Reached 1 after %d steps" steps
Reached 1 after 111 steps

No break or continue

F# loops have no break or continue. Instead, use a while loop with a condition flag, or — more idiomatic — a collection function that stops early:

let numbers = [3; 8; 12; 5; 20]

// "find the first number over 10" — no loop needed
printfn "%A" (numbers |> List.tryFind (fun n -> n > 10))

// "skip the odd ones" — filter instead of continue
for n in numbers |> List.filter (fun n -> n % 2 = 0) do
    printf "%d " n
printfn ""
Some 12
8 12 20

Loops versus functions

// Loop style
let mutable total = 0
for n in 1 .. 100 do
    if n % 3 = 0 then total <- total + n
printfn "%d" total

// Functional style
[1 .. 100] |> List.filter (fun n -> n % 3 = 0) |> List.sum |> printfn "%d"
1683
1683

Both are correct. The functional version has no mutable state and says what it computes; F# programmers generally reach for it first.

Practice

Print a 5-row triangle of stars (*, **, ... *****) using a for loop and String.replicate.

Show solution
for i in 1 .. 5 do
    printfn "%s" (String.replicate i "*")
*
**
***
****
*****