Skip to content

F# Let Bindings Guide — Immutability, Scope, and Variable Declaration

DodaTech Updated 2026-06-28 2 min read

In this tutorial, you will learn about F# Let Bindings Guide. We cover key concepts, practical examples, and best practices to help you master this topic.

F# let bindings create immutable values by default -- variables cannot change after assignment, encouraging Functional Programming patterns where data flows through transformations rather than mutations.

Basic Bindings

// Immutable by default
let x = 10
// x <- 20  // ERROR: x is immutable

// Type inference
let name = "Alice"      // string
let age = 30            // int
let pi = 3.14159        // float
let isActive = true     // bool

// Explicit type annotation
let count: int = 42
let greeting: string = "Hello"

Mutable Variables

// Explicit mutable
let mutable counter = 0
counter <- 5          // OK with <-
counter <- counter + 1
printfn "%d" counter  // 6

Shadowing

// Shadowing creates a new binding
let x = 5
printfn "%d" x      // 5

let x = x + 3       // new binding, not mutation
printfn "%d" x      // 8

// Original x is unchanged
let shadowed = x    // 8

Scope

module ScopeExample

let global = "module level"

let myFunction () =
    let local = "function level"
    if true then
        let inner = "block level"
        printfn "%s" inner  // OK
    // printfn "%s" inner   // ERROR: out of scope
    printfn "%s" local      // OK

Common Mistakes

1. Forgetting mutable

Trying to reassign an immutable binding with <- causes a compile error.

2. Using = instead of <-

= is for binding, <- is for assignment. x = 5 is a comparison, not assignment.

3. Confusing shadowing with mutation

let x = x + 1 creates a new binding. The original value is not modified.

FAQ

{{< faq question="Why are values immutable by default?" >}} Immutability eliminates entire categories of bugs (unexpected state changes, race conditions) and enables safer concurrent programming. {{< /faq >}}

{{< faq question="Can I use mutable collections?" >}} Yes. ResizeArray<T>(), Dictionary<K,V>, and arrays are mutable. But prefer immutable List, Map, and Set. {{< /faq >}}

{{< faq question="What does let return?" >}} let bindings return unit () at the module level. In expressions, let ... in ... returns the value of the in expression. {{< /faq >}}

What's Next

Now learn about F# functions -- pipes, composition, and partial application.

Topic Description Link
Functions Pipes and composition {{< ref "04-functions" >}}
Discriminated Unions Custom types {{< ref "05-discriminated-unions" >}}

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro