Binding of Symbols to Values

Values has its type and could be bound to a symbols to be named and referred by name (using symbol). It is perfectly natural to have more than one name of the same value (synonyms) and to shadow symbols by using the same symbol in a nested scope. Shadowing is NOT overwriting - once bound, symbols cannot be re-bound. Shadowing is creation of another binding in a different (nested) scope.

In classic Lisps we have two special forms for global bindings (define or defvar) and for local bindings (let or letrec).

(define x 3)

which could be used to bind procedures, like any other values (a procedure is a first-class value)

(define inc (lambda (x) (+ 1 x)))

In the ML family of languages, especially in Ocaml and Haskell binding forms are uniform.

let ... = ...
let ... = ... in ...

in Scheme let is just an abbreviation for implicit lambda and in-place invocation of it with actual argument values.

(let ((x 2))
     (+ 1 x))

is just

((lambda (x) (+ 1 x)) 2)

which is invocation of in-place created procedure.

Notice, that it x is indeed a local binding (a formal parameter of a procedure) and it shadows the symbol x defined in globally.

let x = 2 in x + 1

has exactly the same semantics, and

let inc x = x + 1

is semantically the equivalent to (define inc (lambda (x) (+ 1 x)))

Like any other expressions, lets could be nested

let ... = ... in
   let ... = ... in
      let ... = ... in ...

which is just nesting of lambdas

The let* special form, which evaluates all of its bindings simultaneously (in the same environment) has corresponding syntax with the and keyword.

let ... = ... and ... = ...

Recursive procedures could be defined with the special keyword rec in the let expression

let rec ... = ... 

which is equivalent to the letrec special form in Scheme.

Last modified 2 years ago Last modified on Oct 7, 2018, 3:11:17 AM
Note: See TracWiki for help on using the wiki.