Esc
Start typing to search...

Variables

Variables in Keel are bindings that associate names with values. By default, all bindings are immutable.

Declaring Variables

Use let to declare a variable:

let name = "Alice"

let age = 30

let pi = 3.14159

pi
Try it

Type Annotations

Keel has strong type inference, but you can add explicit type annotations:

let count = 42

let message = "Hello"

let ratio = 0.75

ratio
Try it

Type annotations are optional but can improve code clarity and catch errors earlier.

Variable Shadowing

To "update" a variable, use variable shadowing by re-declaring it with the same name:

let x = 10

let x = x + 5

x  -- 15
Try it

Variables itself are immutable. Shadowing creates a new variable that hides the previous one.

let x = 1

let x = x + 1

let x = "hello"  -- x can change type when shadowed

x  -- "hello"
Try it

Note: Only variables support shadowing. Functions, modules, and type definitions do not allow shadowing — redeclaring them with the same name is an error.

Scope

Variables are block-scoped. A variable is only accessible within the block where it's defined:

fn example : Int -> Int
fn example x =
    let inner = x + 1
    inner

inner  -- Error: `inner` is not in scope
Try it

Let Expressions

In Keel, let is an expression that introduces bindings:

let area =
    let width = 10
    let height = 5
    width * height

area  -- 50
Try it

The value of a let block is the value of its final expression.

Multiple Bindings

You can chain multiple let bindings:

let x = 1

let y = 2

let z = 3

x + y + z
Try it

Destructuring

Variables can be bound using pattern matching (destructuring):

Tuple Destructuring

let (x, y) = (10, 20)

x  -- 10
Try it

Record Destructuring

let { name, age } =
    { name = "Bob", age = 25 }

name  -- "Bob"
Try it

Nested Destructuring

let (x, { a, b }) =
    (1, { a = 2, b = 3 })

a  -- 2
Try it

Best Practices

  1. Use descriptive names: userName is better than u
  2. Use shadowing for transforms: Chain let x = ... to transform values step by step
  3. Keep scopes small: Define variables close to where they're used
  4. Use type annotations for public APIs and complex expressions
  5. Use destructuring to extract values from tuples and records

Next Steps

Learn about operators to combine values.