OCaml Class 1: let-Bindings

Global vs Local

There are two type of let binding: global and local.

Global Local
let name = value let name = value in expression

Global let

A name defined via a global let is defined up to the end of the source file (except where shadowed).

Local let

A name defined via a local let is defined only within the attached expression.

Legend: let name = expr1 in expr2

Local let's can nest:

Functions being values, you can of course define local functions:

Confused? You can always redundantly parenthesize:

(But this is unidiomatic.)

A local let is itself an expression:

This is why they can nest.

Shadowing

Since let's can nest, inner names can shadow identical outer names.

A local let can shadow a global one:

let n = 100
let print100 () = print_int n
let print6 () = let n = 6 in print_int n

Global let's can shadow too:

let f x = x + 1
let f x = x ^ "\n"

Recursive let

What happens if the name being defined occurs on the right-hand side of the equals sign (but not after the in), as in this (broken) recursive function definition?

      let f x = x * f x in f 6

Answer: the green f is not the same as the blue f! The blue f is either undefined, or a different, previously defined f:

      let f x = x + 1 in
        let f x = x * f x in
          f 6

The value of the above expression is 42.

let rec

Ordinary non-recursive let is useful for re-defining values; especially handy when working interactively. But to write a recursive function, you need to use let rec. Here is factorial:

    let rec fac n =
      if n = 1 then
        1
      else
        n * fac (n - 1)