CS 611 Advanced Programming Languages Class Notes 15 Fall 1993 Robert L.

Constable October 18, 1993 Kenji Saito, Scribe

1 Heart of Pure Lisp
Recall that we called -calculus the amoeba of programming languages. In fact, the semantics of high level programming languages are all based on -calculus. Lisp and Scheme are actually inspired by -calculus. We are going to talk about the heart of pure Lisp. Lisp has many dialects, but there is a common dialect called Common Lisp. Common Lisp is famous for having a very thick document, but somewhere in the thick document, there lies the tiny core of the language { the heart of pure Lisp. We are going to focus on this tiny part of the language. The rst Lisp interpreter, Lisp 1.5, was accidentally implemented by a graduate student of John McCarthy, the designer of Lisp. The document of Lisp 1.5 had only 15 pages. It is said that McCarthy misunderstood untyped -calculus, and his mistakes were often corrected by his students. However, he understood something more fundamental { that -calculus is powerful enough to be the basis of programming langauges, and it is also very simple to implement.

2 Syntax
Recall that we have the following two primitives in -calculus: 1. (v:b) 2. ap(f ; a) These two are used to describe the semantics of -calculus, and sometimes referred as M-expressions. The \M " is for \metalanguage". In Lisp, the above two are denoted respectively as follows: 1. (LAMBDA (v) b) 2. (f a) These are syntactic expressions of M-expressions, and are called S-expressions1. In S-expression, the rst position between `(' and `)' has a special meaning: if it is LAMBDA, then the expression is an abstraction; otherwise, the expression is an application. In real Lisp, multiple parameters and function bodies are utilized as follows:
s ;s ;:::; s n > s1 s2 ::: s

In Lisp, S-expression is de ned inductively as follows: 1. An atom is an S-expression. 2. If 1 2 and n ( 1) are S-expressions, then ( Atom will be de ned in the following lecture.


is an S-expression.


1. (LAMBDA (v1 : : : vn ) b1 : : : bm) (n; m 0) 2. (f a1 : : : an) (n 0) where v's denote multiple formal parameters, b's denote multiple bodies which are evaluated sequentially, and a's denote multiple actual parameters. However, in this lecture, we will not use multiple parameters nor function bodies, and we will use the following (prettier) display form for S -expressions: 1. ( (v) b) 2. (f a) We can de nitely see the similarity between these S-expressions and M-expressions; in the above, v is the binding variable, b is its scope, f is the function part of an application, and a is its argument.

3 Semantics
3.1 Overview
It is the semantics where we depart signi cantly from what we have done previously in the class; we would naturally expect the following reduction for an S-expression: (( (v) b) a) ! b a=v] but this is not how Lisp works; we need the concept of environments. Intuitively, Lisp computes an expression b in some environment where v := value of a. The semantics of Lisp is characterized by an interaction between the following two functions: 1. eval(exp; env) where exp is an expression, and env is an environment 2. apply(proc; arg) where proc is the internal representation of an abstraction (called procedure), and arg is an argument eval and apply are so-called yin and yang of the semantics of Lisp. Intuitively, an environment works as follows: 1. We x the set of constants (e.g. 0; 1; 2; : : :) and operators (e.g. +) in every environment. 2. An environment has de nitions of symbols; the following is an example of an environment: + 0; 1; 2; : : : de ne x = 2 de ne g = ( (v) v + 2) de ne h = ( (v) v + 1) 2

3.2 Environment

3. We can ask queries such as \give me the value of (g (h x))" in a given environment. O cially, Lisp environment is de ned as follows: 1. An environment is a list of frames. 2. A frame is a list of bindings. 3. A binding is a pair (variable value). For example, the following is an environment:

(((x 2)(y 3)) | x 3)(y 2))) (( {z } {z } |
frame1 frame2

environment }|


We de ne the following functions to operate upon an environment: 1. look up value(v; env) returns the value of a variable v in an environment env; v is searched from the top of env. 2. extend env(v; value; env) adds a frame ((v value))2 to an environment env. Note that the value of a variable in an environment can be overwritten by adding a frame to the top of the environment.

3.3 Procedure

Intuitively, a procedure is a package including a function and its environment; sometimes it is called a closure. The function to construct a procedure is de ned as follows:

make proc(exp; env) = ((formal Jparameter(exp)body(exp)) env) | {z }
where body(exp) gives the body of an expression exp and its formal parameter. Function eval is de ned as follows: eval(exp; env) = 1. if is variable(exp) then look up value(exp; env) 2. if is lambda(exp) then make proc(exp; env) 3. if is compound(exp) then apply(eval(operator(exp); env); eval(operand(exp); env)) where is lambda is the same as is abs, is compound is the same as is ap, operator is the same as function part, and operand is the same as argument.
Since we are not going to use multiple parameters, a frame will be a binding rather than a list of bindings to simplify notations henceforth.


3.4 Evaluation


3.5 Application

Function apply is de ned as follows:

apply(proc; arg) = eval(proc body(proc); extend env(proc parameter(proc); arg; proc env(proc))) where proc body returns the body of the procedure, proc parameter returns the formal parameter of the procedure, and proc env returns the environment of the procedure. So, apply(((v; b); e); a) is eval(b; e + fv := ag)3; there is no capture here, since a is already evaluated according to the de nition of eval where the expression is a compound.


In the following lecture, this is more precisely written as

eval b; v a

( ( )@ ) where @ is an append operator.