Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
104 lines (76 sloc) 1.89 KB
title
Bindings

On the Subject of let and let rec

The let and let rec statements introduce new names into the current scope. In other words, they let you declare new bindings (quite similar to constants in other languages).

Syntax

let name1 = value1 [, name2 = value2]
let rec name1 = func1 [and name2 = func2]

Parameters

name1, name2, ..., nameN Names to be used for the binding identifiers.

value1, value2, ..., valueN Any valid Grain expression.

func1, func2, ..., funcN Any valid Grain functions.

Description

let allows you to introduce names, and let rec allows you to introduce recursive definitions.

Using let

Using let is pretty simple:

# Assigning the value 5 to the name 'foo'
let foo = 5

# Assigning the value of name 'foo' to name 'bar'
let bar = foo

# Assigning this function to the name 'add2'
let add2 = (a, b) => a + b

# Assigning the result of this block to the name 'baz'
let baz = {
  let a = 5;
  let b = 6;
  a * b
} # baz is now the value 30

let is scoped to the nearest block. That really just means it's scoped to the nearest enclosing curly braces:

let a = {
  # This is allowed, since this 'a' only exists within the enclosing braces.
  let a = 3;

  let b = 4;
  a + b
}

a # This evauluates to 7.

b # This is a name error, since 'b' only existed in the earlier block.

Using let rec

let rec primarily allows you to define recursive functions. The name of the identifier used will be within the scope of the body of the function:

let rec fib = (n) => {
  if (n < 2) {
    n
  } else {
    fib(n-1) + fib(n-2)
  }
}

let rec also allows you to define mutually recursive functions:

let rec isEven = (n) => {
  if (n > 1) {
    isOdd(n-1)
  } else {
    n == 0
  }
}
and isOdd = (n) => {
  if (n > 1) {
    isEven(n-1)
  } else {
    n == 1
  }
}