purpose programming language it would be foolish to abandon either.
LAMBDA
, Actors, and Continuations
Suppose that we choose a set of primitive operators which are not functions. This will surely produce a radical change in our style of programming, but, by the argument of the previous section, it will not change our interpretation of LAMBDA
and function calling. A comparison between our view of LAMBDA
and the notion of actors as presented by Hewitt will motivate the choice of a certain set of non-functional primitives which lead to the so-called "continuation-passing" style.
Actors ≡ Closures (mod Syntax)
In [Sussman 75] Sussman and Steele note that actors (other than those which embody side effects and synchronization) and closures of LAMBDA
expressions are isomorphic in their behavior. Smith and Hewitt [Smith 75] describe an actor as a combination of a script (code to be executed) and a set of acquaintances (computational quantities available to the code). A LISP closure in like manner is a combination of a body of code and a set of variable bindings (or, using our idea of renaming, a set of computational quantities with (possibly implicitly) associated names). Hewitt [Hewitt 76] has challenged this isomorphism, saying that closures may contain unnecessary quantities, but I have already dealt with this issue above.
Let us therefore examine this isomorphism more closely. We have noted above that it is more accurate to think of the caller of a LAMBDA
as performing a GOTO
rather than the LAMBDA
itself. It is the operation of invocation that is the transfer of control. This transfer of control is similar to the transfer of control from one actor to another.
In the actors model, when control is passed from one actor to another, more than a GOTO
is performed. A computed quantity, the message, is passed to the invoked actor. This corresponds to the set of arguments passed to a LAMBDA
expression. Now if we wish to regard the actor/LAMBDA
expression as a black box, then we need not be concerned with the renaming operation; all we care about is that an answer eventually comes out. We do not care that the LAMBDA
expression will "spread" the set of arguments out and assign names to various quantities. In fact, there are times when the caller may not wish to think of the argument set as a set of distinct values; this attitude is reflected in the APPLY
primitive of LISP, and in the FEXPR
calling convention. The actors model points out that, at the interface of caller and callee, we may usefully think of the argument set as a single entity.
In the actors model, one important element of the standard message is the continuation. This is equivalent to the notion of return address in a LISP system (more accurately, the continuation is equivalent to the return address plus all the quantities which will be needed by the code at that address). We do not normally think of the return address as an argument to a LAMBDA
expression, because standard LISP notation suppresses that fact.
On the one hand, though, Steele and Sussman [Steele 76] point out that it is possible to write LISP code in such a manner that return addresses are passed explicitly. (This style corresponds to the use in PLASMA of ==>
and <==
to the exclusion of =>
, <=
, and functional notation.) When code is written in this "continuation-passing style", no implicit return addresses are ever created on the control stack. all that is necessary to write code entirely in this style is that continuation-passing primitives be available.