Functions
Prerequisites: if/then/else expressions
Functions are defined with let, just like values. Parameters are
separated by spaces, not commas, and so are the arguments when you
call it:
let square x = x * x
let add a b = a + b
let greet name = printfn "Hello, %s!" name
printfn "%d" (square 6)
printfn "%d" (add 2 3)
greet "Ada"
36
5
Hello, Ada!
- There's no
returnkeyword: a function returns the value of its last expression. - Wrap a call in parentheses when it's an argument to another function:
printfn "%d" (square 6). Without them, F# would readsquareand6as two separate arguments toprintfn.
Multi-line functions
let bmi weightKg heightM =
let value = weightKg / (heightM * heightM)
let category =
if value < 18.5 then "underweight"
elif value < 25.0 then "normal"
else "overweight"
sprintf "%.1f (%s)" value category
printfn "%s" (bmi 70.0 1.75)
22.9 (normal)
Local values like value and category exist only inside the function.
Signatures
In F# Interactive, a function's type shows its parameters and result separated by arrows:
val square: x: int -> int
val add: a: int -> b: int -> int
val bmi: weightKg: float -> heightM: float -> string
Read int -> int -> int as "takes an int, then an int, and returns an
int". The next lessons explain why it's written as a chain.
Recursion needs rec
A function that calls itself must be marked rec:
let rec factorial n =
if n <= 1 then 1
else n * factorial (n - 1)
let rec countdown n =
if n > 0 then
printf "%d " n
countdown (n - 1)
else
printfn "liftoff!"
printfn "%d" (factorial 5)
countdown 3
120
3 2 1 liftoff!
Functions with no parameters
A function that takes no input takes unit:
let sayHi () = printfn "Hi!"
sayHi ()
sayHi ()
Hi!
Hi!
Without the (), let sayHi = printfn "Hi!" would be a value: it
would print once, immediately, and never again.
Practice
Write a function isLeapYear year (divisible by 4, except centuries,
unless divisible by 400) and print the result for 1900, 2000, and 2024.
Show solution
let isLeapYear year =
(year % 4 = 0 && year % 100 <> 0) || year % 400 = 0
printfn "%b %b %b" (isLeapYear 1900) (isLeapYear 2000) (isLeapYear 2024)
false true true