Subject: Re: tail-call optimization (was Re: What is dynamic-wind ?)
From: (Rob Warnock)
Date: 12 Feb 2002 02:16:40 GMT
Newsgroups: comp.lang.scheme
Message-ID: <a49tu8$au07q$>
Doug Quale  <> wrote:
| David Feuer <> writes:
| > I don't really understand what tail-call optimization (the
| > compilation/interpretation technique) really has to do with Scheme (the
| > language).
| As you suspect, you have to look at the history of Scheme to answer
| this question.  In 1975 Guy Steele and Gerald Sussman were designing
| and writing some experimental lisp interpreters and compilers...
| Better yet go to and read all
| of the lambda papers on that page.  Scheme's recorded history goes
| back to 1975.  In 1975 I was still in high school so I didn't see
| these papers until a few years later when I was in college.  Still, to
| someone who was programming in Pascal at the time, "The Art of the
| Interpreter, or the Modularity Complex (Parts Zero, One, and Two)"
| made a tremendous impression on me.  Scheme changed the way that I
| thought about programming and computing forever.

In particular, in those very papers it is stated explicitly that
tail-call optimization was what allowed the merger of the ideas
of "actors" and "procedures". [Early Scheme was largely about
experimenting with "actors".] *If* (and only if) procedure calls
in tail position were equivalent to "jump-with-arguments", then
"actors" (stateful objects that were sent messages) and "procedures"
turned out to be *identical* in the implementation of that early
interpreter. At which point, Steele realized he could get rid of
a separate "actor" object type, and just use (TCO-safe) procedures.

| Anyone who chooses not to implement TCO is perfectly free to do so.
| The resulting language may look a lot like Scheme, but it won't be Scheme.
| In Scheme, proper implementation of tail recursion is non-negotiable.

Exactly so. IMHO.

An example of "actor-like" procedures is a long-running finite-state
machine written as one procedure per state, somewhat in this style:

	(define (stateXXX entry-event)
	  (begin stuff we always do when entering this state,
		    possibly conditioned by "entry-event"...)
	    (let ((x (get-next-event)))
	      (case x
		((this) something [perhaps output?]...
		 (stateYYY x))	; switch to state YYY
		((that) something...
		 (stateZZZ x))	; switch to state ZZZ
		((the other things) something with one of {the,other,things}...
		 (stateWWW x))	; switch to state WWW
		 ...maybe output, maybe not...
		 (stateXXX x))))) ; loop in state XXX

	(define (stateYYY entry-event) ...whatever...)
	(define (stateZZZ entry-event) ...whatever...)
	(define (stateWWW entry-event) ...whatever...)

You can view the "entry-event" as a "message" "sent" to the next-state
"actor", or as a parameter to a tail-called procedure, your choice.
*Because* Scheme guarantees TCO, the above will not run out of space,
no matter how long the state machine runs [good plan, if the state
machine is, say, an operating system!!].


Rob Warnock, 30-3-510		<>
SGI Network Engineering		<>
1600 Amphitheatre Pkwy.		Phone: 650-933-1673
Mountain View, CA  94043	PP-ASEL-IA