Variables and Bindings

De Bruijn Indices

Goth uses de Bruijn indices for variable references. Variables are accessed by their binding depth, eliminating shadowing ambiguity.

Syntax Meaning
or _0 Most recently bound variable
or _1 Second most recent
or _2 Third most recent
λ→ ₀              # identity: returns its argument
λ→ λ→ ₀ + ₁      # add: ₀ is inner arg, ₁ is outer arg

In multi-argument declarations, is the last (most recently bound) argument:

╭─ sub : ℤ → ℤ → ℤ
╰─ ₁ - ₀            # ₁ = first arg, ₀ = second arg (sub 10 3 = 7)

Let bindings shift indices:

╭─ example : ℤ → ℤ
╰─ let x = ₀ × 2 in    # ₀ = argument
   let y = ₀ + 1 in    # ₀ = x, ₁ = argument
   ₀ + ₁               # ₀ = y, ₁ = x, ₂ = argument

Let Bindings

Simple let:

let x = 5 in x × x
# Result: 25

Sequential bindings (with semicolons):

let x ← 5 ;
    y ← x × 2 ;
    z ← y + 1
in x + y + z
# Result: 26

Both = and work identically for bindings.

With type annotation:

let x : F = 5.0 in x × 2
let v : [3]F64 = [1.0, 2.0, 3.0] in v

Recursive Bindings

let rec enables self-referencing and mutually recursive definitions:

let rec factorial ← λ→ match ₀
              0 → 1
              n → n × factorial(n - 1)
in factorial 5
# Result: 120

Mutual recursion:

let rec even ← λ→ match ₀
                0 → ⊤
                n → odd(n - 1) ;
        odd ← λ→ match ₀
                0 → ⊥
                n → even(n - 1)
in even 10
# Result: ⊤