F# variables
last modified May 3, 2025
In this article, we explore how to effectively work with variables in F#. Variables are fundamental building blocks in any programming language.
A variable is a named storage location that holds a value. In F#,
variables are immutable by default, meaning their values cannot be
changed after initialization. However, mutable variables can be created using
the mutable
keyword. F# uses type inference to determine variable
types, but explicit typing is also supported.
F# immutable variable
Immutable variables are the default in F#. Once assigned, their value cannot change.
let x = 5 let name = "John Doe" let active = true printfn "%d" x printfn "%s" name printfn "%b" active
The program defines three immutable variables of different types: integer, string, and boolean. We then print their values.
let x = 5
This creates an immutable integer variable x with value 5. The let keyword is used for variable declaration.
λ dotnet fsi immutable.fsx 5 John Doe true
F# mutable variable
Mutable variables can have their values changed after initialization.
let mutable counter = 0 printfn "Initial value: %d" counter counter <- counter + 1 printfn "After increment: %d" counter counter <- counter + 1 printfn "After second increment: %d" counter
We create a mutable counter variable, increment it twice, and print its value at each step.
let mutable counter = 0
The mutable keyword makes the variable changeable. Without it, this would be a compilation error.
counter <- counter + 1
The <- operator is used to assign new values to mutable variables.
λ dotnet fsi mutable.fsx Initial value: 0 After increment: 1 After second increment: 2
F# variable type annotation
F# supports explicit type annotations for variables.
let age: int = 34 let name: string = "Roger Roe" let height: float = 172.5 printfn "%s is %d years old and %.1f cm tall" name age height
We declare three variables with explicit type annotations and print them.
let age: int = 34
The colon followed by the type specifies the variable's type explicitly.
λ dotnet fsi typed.fsx Roger Roe is 34 years old and 172.5 cm tall
F# variable scope
Variables in F# have block scope, visible only within their defining block.
let outer = "I'm outside" if true then let inner = "I'm inside" printfn "%s" inner printfn "%s" outer // printfn "%s" inner // This would cause an error printfn "%s" outer
The example demonstrates variable scoping in F#. The inner variable is only accessible within the if block.
let inner = "I'm inside"
This variable is only visible within the if block where it's defined.
λ dotnet fsi scope.fsx I'm inside I'm outside I'm outside
F# variable shadowing
F# allows shadowing - declaring a new variable with same name in narrower scope.
let x = 10 printfn "Outer x: %d" x let innerFunction () = let x = 20 printfn "Inner x: %d" x innerFunction() printfn "Outer x again: %d" x
We demonstrate variable shadowing by creating a new x inside a function.
let x = 20
This creates a new x that shadows the outer x within the function's scope.
λ dotnet fsi shadowing.fsx Outer x: 10 Inner x: 20 Outer x again: 10
F# tuple variables
Tuples allow grouping multiple values into a single variable.
let person = ("John Doe", 34, "gardener") printfn "Full tuple: %A" person let name, age, occupation = person printfn "Name: %s, Age: %d, Occupation: %s" name age occupation let first, _, _ = person printfn "Just the name: %s" first
We create a tuple variable and demonstrate different ways to access its values.
let person = ("John Doe", 34, "gardener")
This creates a tuple containing three values of different types.
let name, age, occupation = person
This destructures the tuple into individual variables.
λ dotnet fsi tuples.fsx Full tuple: ("John Doe", 34, "gardener") Name: John Doe, Age: 34, Occupation: gardener Just the name: John Doe
F# reference cells
Reference cells provide an alternative way to handle mutable state.
let counter = ref 0 printfn "Initial value: %d" !counter counter := !counter + 1 printfn "After increment: %d" !counter counter := !counter + 1 printfn "After second increment: %d" !counter
We create a reference cell, then modify and access its contents.
let counter = ref 0
Creates a reference cell initialized with value 0.
!counter
The ! operator dereferences the cell to access its value.
counter := !counter + 1
The := operator updates the reference cell's value.
λ dotnet fsi refcells.fsx Initial value: 0 After increment: 1 After second increment: 2
F# variable naming conventions
F# follows certain naming conventions for variables.
let camelCaseVariable = "camelCase" let PascalCaseVariable = "PascalCase" let snake_case_variable = "snake_case" let ``variable with spaces`` = "works with backticks" printfn "%s" camelCaseVariable printfn "%s" PascalCaseVariable printfn "%s" snake_case_variable printfn "%s" ``variable with spaces``
The example shows different naming styles supported in F#.
let ``variable with spaces`` = "works with backticks"
Backticks allow using spaces and other special characters in variable names.
λ dotnet fsi naming.fsx camelCase PascalCase snake_case works with backticks
In this article we have worked with variables in F#.