Skip to content
Matt Bierner edited this page Apr 9, 2014 · 9 revisions

The let expression binds variables in an expression, and can be used wherever an expression may appear.

2 + let a = 3 in a * 10; // 32

The body of the let expression captures as much as possible to its right, and let expressions are right associative:

let a = 3 in let b = 4 in a + b;
// is the same as
let a = 3 in (let b = 4 in a + b);

Multiple Bindings

Multiple values can be bound in a single let expression. Bound values are evaluated left to right and previously bound values can be used in the current binding:

// These are the same
let a = 3, b = 5 in a + b;
let a = 3 in let b = 5 in a + b;

// Using an existing binding.
let a = 3, b = a + 10 in a + b;
let a = 3 in let b = a + 10 in a + b;

// Rebinding a value using existing value
let a = 3, a = a + 5 in a; // 8

Capture

Let expressions capture as much as possible to their right.

4 * let a = 2 in a + 3;
4 * (let a = 2 in a + 3); // 20
4 * (2 + 3); 

Capture can be limited by wrapping the entire expression in parentheses:

4 * (let a = 2 in a) + 3;
4 * 2 + 3; // 11

Unpacks

Let expression bindings may use any unpack pattern on their left hand side:

let
    o#{x, y} = {'a': 3, 'x': 6, 'z': 5, 'y': 8},
    [first] = [1, 2, 3]
in
   first + y + x + o.a; // 18

Scope and Evaluation

Let expressions introduce a new scope for the bindings and body. Bindings may hide existing bindings for the duration of the expression. Use of let expression bindings outside of the expression is not valid.

var a = 14
let a = 3 in a * a; // 9

Bound values will only be evaluated once no matter how many times they are used. Evaluation is in-order, left to right.

Recursive Bindings

Recursive bindings allow a binding to access itself in its value. This is only useful when the value is a function. Recursive bindings use the := operator in place of =.

// Normal binding. This is an error since `fib` in undefined in the function body.
let
    fib = \x -> ?x < 2 :x :(fib(n - 1) + fib(n - 2))
in
    fib(10);

// Using a recursive binding fixes this
let
    fib := \x -> ?x < 2 :x :(fib(n - 1) + fib(n - 2))
in
    fib(10);

Named functions can always access themselves by function name. The scope of the function name is limited to the evaluation of the bound value.

let fib = function impl \x -> ?x < 2 :x :(impl(x - 1) + impl(x - 2)) in
    fib(10);
Clone this wiki locally