Lambda Reference
Bill Majoros
September 8, 1999
Introduction
This is a brief reference for the language lambda, which is an implementation
of the lambda calculus. The lambda calculus is an abstract
language consisting of only three constructs: lambda expressions (lambda
(x) <expr>), function calls (<f> <x>), and atoms, which are variables
and literals.
The lambda calculus is normally just used in programming textbooks to
teach abstract concepts of programming languages and interpreters.
However, lambda, which is the basis for LISP and Scheme, can be implemented
to act as a real programming language, which, given a suitable set of primitives,
can support arbitrary computation.
The advantage of lambda is that it has such a simple and consistent
syntax that it is relatively easy to implement an intrepter for it.
Because it is Turing-complete, it can easily be used for Genetic Programming,
a form of Genetic Algorithms used for evolving algorithms. The present
implementation of the language is written in C++, and provides an API for
C++ programs to communicate with lambda, so that Genetic Programming can
now be done in an efficient language like C++, while still evolving LISP-like
expressions.
Identifiers
An identifier can be any sequences of letters, digits, ?, -, and possibly
other characters (I don't remember at the moment).
Literals
1. Character Literals
#a is the character a. #\n is the newline. You can also
use #\r, #\t, #\\, #', and #".
2. Numeric literals
An integer is something like 123 or -123. A real number is something
like 3.14.
3. String literals
A string literal is something like "Hello, world."
4. Symbols
A symbol literal is something like 'x. A symbol is not a variable;
it does not stand for something. It just stands for itself.
However, if you (define 'x 6), because of the semantics of the define function,
the variable x (not the symbol, 'x) will come to be bound to 6. But
the symbol 'x is still just the symbol 'x, and stands for nothing but itself.
Lambda Expressions
A lambda expression is a function literal. Such a function literal
is a first-class object, because it can be stored in data structures
and executed later. A lambda expression can occur anywhere in a program
that any other literal can occur.
A lambda expression is denoted by a set of square brackets containing
a parameter list, followed by a vertical bar (|), followed by the function
body, which may consist of one or more expressions. The last expression
is the value returned by the function. All the expressions are evaluated
left-to-right, so this feature can be use to execute statements sequentially.
For example, this line:
[x y z | (print x) (print y) (print z)]
will print x, followed by y, followed by z.
If-Then-Else
Lambda has no built-in if-then-else construct, but it is easy to get the
same functionality using lambda expressions.
The pre-defined if function takes 3 arguments. It evaluates
the first, and if it evaluates to true, it executes the second parameter,
otherwise the third. For example:
(if (< x 10) [|(print "less than ten")] [|(print "not less than ten")]
First, the (< x 10) is evaluated. The then and
else
parts are not immediately executed, because they occur inside lambda constructs.
They will be wrapped in closures and passed as first-class objects into
the if function as its second and third parameters. The appropriate
clause (then or else) will be called by if (with no
arguments) depending on the value of the first argument.
True and False
True and false are not built into the lambda language, so it uses 1 to
denote true and nil to denote false. However, two predefined
variables, true and false, are bound to these values, so
that they may be used in your programs.
nil
The value nil represents the absence of an object.
It is equivalent to NULL in C++ and nil in Smalltalk.
Function Invocation
A function is invoked by listing the function followed by its arguments
within parentheses:
(f x y z)
This will call the function currently bound to f, passing in the values
currently bound to x, y, and z as it arguments.
Equality
Two distinct objects may have the same value, but they are still two different
objects. Thus, if you compare 6 and 6 using the = function, as in
(= 6 6), the value will be true. However, if you execute (eq? 6 6),
the value will be false, because both instances of '6' will evaluate to
a new 6 object, and those objects have different addresses. Thus,
eq? compares addresses of objects, and evaluates to true only when both
of its arguments evaluate to the address of one object.
Lists
One of the few built-in types in lambda is the cons cell, also called
a dotted pair. A cons cell is an ordered pair of object pointers.
It is denoted in print by (a . b), but this is not legal lambda syntax,
so you may not use this in a lambda program. To create a cons cell
containing objects a and b, use (cons a b).
A list can easily be constructed by creating a series of cons cells,
where the first element of each pair points to an object to be stored in
the list, and the second element of the pair points to the next pair in
the list. The second element of the very last pair in the sequence
should be nil, to terminate the list. When a sequence of cons cells
are set up in this way, the result is referred to as a list, but when a
cons cell has something other than a another cons cell as its second element,
it is instead referred to as an improper list. An improper
list may have a sequence of cons cells but be terminated by something other
than nil. Only when the last cell is terminated by nil is it called
a true list.
For example, this is a list: (cons 1 (cons 2 (const 3 nil))).
It contains the numbers 1, 2, and 3. However, this is an improper
list: (cons 1 2), and so is this: (cons 1 (cons 2 3)).
Comments
A comment begins with a semicolon and extends to the end of the line.
Built-in Functions and Objects
(print x) ; prints x to standard out
(if x y z) ; if x evaluates to non-nil, evaluates and
returns y, else z
(note that y and z must be enclosed in lambda constructs)
nil ; no object = false = a NULL pointer
true ; evaluates to 1
false ; evaluates to nil
(cons x y) ; returns a list just like y, but with x at
the front
(car x) ; returns the first element in list x
(cdr x) ; returns the sublist of x starting with the
second element
(+ x y) ; addition
(- x y) ; subtraction
(* x y) ; multiplication
(/ x y) ; division
(% x y) ; modulus (integer remainder)
(define 'x y) ; binds variable x to whatever y evaluates
to
(< x y) ; less than
(<= x y) ; less than or equal to
(> x y) ; greater than
(>= x y) ; greater than or equal to
(= x y) ; converts x and y to real numbers and then tests
for equality
(!= x y) ; not equal (for real numbers)
(load filename) ; loads a file with name given
by string arg filename
(eq? x y) ; tests if x and y evaluate to the same
object
(nil? x) ; tests whether x evalutes to nil
(list? x) ; tests whether x is a true list (i.e., a sequence
of cons cells)
(is-cons-cell? x) ; tests whether x is a cons cell
(sin x) ; returns the sin of x
(cos x) ; cosine of x
(sqrt x) ; square root of x
(acos x) ; inverse cosine of x
(asin x) ; inverse sin of x
(atan2 x y) ; inverse tangent of y/x (using sign of x
and y to determine quadrant)
(exp x) ; e (the Euler number) to the power x
(log x) ; natural logarithm (i.e., base e) of x
(log10 x) ; log base 10 of x
(pow x y) ; x to the y
(ceil x) ; round x up to nearest integer
(floor x) ; round x down to nearest integer
(fabs x) ; absolute value of real value
(abs x) ; absolute value of integer (returns integer)
(make-vector x) ; returns a new vector containing x elements
(all nil)
(vector? x) ; tests whether x evalutes to a vector
(vector-ref v i) ; returns element i of vector v (zero-based)
(vector-set v i x) ; stores x at location i in vector
v (zero based)
(vector-length v) ; returns length of vector v
(vector-to-list v) ; returns a list containing the elements
of v
(list-to-vector x) ; returns a vector containing the
elements of list x
(set-local 'lp x) ; stores x at lexical position lp in
innermost scope (advanced)
(set-enclosing d p x) ; stores x at lexical address (:
d p) (advanced)
(random-real) ; random real between 0 and 1
(random-int x) ; random integer between 0 and x-1, inclusive
(protected-div x y) ; divides x by y, returning x if
y is zero