Session 30
Back to the Future

The Last Opening Exercise

One last chance to practice for the final exam, with a useful result:

Write a function named (cons-at-end v lst) that returns a new list containing the items in lst followed by v.
list ::= ()
       | (item . list)
For example:
> (cons-at-end 'e '(a b 1 d))
'(a b 1 d e)

> (cons-at-end 'a '())
'(a)

Your function can be recursive or use higher-order functions.

Humor me.

You can use (cons-at-end v lst) in the constructor for do expressions on Homework 11.

This code file contains a couple of solutions, plus some help with the tricky accessor for do expressions.

Today

on the left, a photo of young Harry Potter, holding a book and a wand, captioned 'Eugene on the first day'; on the right, a photo of Daniel Radcliffe in the street, wearing a bathrobe and fuzzy slippers, brandishing a gun in each hand, captioned 'Eugene on the last day'
Eugene uses the crazy Harry Potter meme to describe his semester

I usually start the semester brimming with energy and excitement. By the end of the semester, I feel like a crazed madman. But like you...

on the left, a photo of young Harry Potter, holding a book and a wand, captioned 'Eugene on the first day'; on the right, a photo of Daniel Radcliffe in the street, wearing a bathrobe and fuzzy slippers, brandishing a gun in each hand, captioned 'Eugene on the last day'
ah, the deep sleep of the innocent

... I'm really just tired. A good kind of tired, after a semester thinking interesting thoughts and learning new things.

Today we take the idea of our Boom interpreter, and our study of programming languages, back to their historical beginning. In doing so, we will see one of the great intellectual achievements in computer science, one that has changed the world.

Along the way, I'll ask you to do one last exercise. No code, I promise.

What of Boom?

The album cover of Hall and Oates's 1984 album Big Bam Boom.
We've had no mentions of Hall and Oates
in class yet this semester.
I can't go for that.

If crazed Eugene, the one in the bathrobe and slippers, were behind the wheel today, we would tackle one more big task.

With the completion of Homework 11, you will have implemented an interpreter for Boom, a language for manipulating numbers.

The language consists of three primitive values, number literals, unary operations, binary operations, variable references, and blocks that support local variables and assignment statements.

The interpreter consists of a preprocessor, an evaluator, and a REPL, all three of which operate over the abstract syntax of the language.

That's two long lists. You can be proud!

Boom is a limited language, but we can now use it to play with numbers and solve simple number problems.

I have answered a couple of questions several times in the last few days, one from the beginning of the assignment and one from the middle:

Are we done? For the semester, yes, but Boom could be much more. The programmer in me really wants to take the next steps. What would happen if we:

Now that Boom supports local variables in an environment, adding functions to the language is especially tempting...

Walk through the steps for adding functions to the language.

Our REPL would fast become... a full-fledged interpreter! And Boom would fast becoming a real language.

You've implemented most of it, and you know how to implement the rest. We've come a long way in fifteen weeks.

A Quick Closing Survey

a meme of Phil Dunphy from Modern Family misunderstanding texting slang
I'm a hip dad.
(Don't ask my daughters.)

Answer three quick questions for me:

You might answer the last one in different ways:

Please answer seriously and honestly. This will help me improve the course.

The Past is Prologue

a three-panel XKCD comic on Lisp and Perl
XKCD on the creation of the universe: God crushes the Lisper's dream

The duality of program and data means that anyone can create a language and write an interpreter for it.

This is not a new idea. It is one of the oldest ideas in computer science. People began to write language interpreters and compilers in the middle 1950s, in assembly language. Soon after that, John McCarthy realized something that gave the idea its full power: we can write a language interpreter in the language being interpreted.

Actually, McCarthy did more: he defined the features of a new language, Lisp, in terms of the language features themselves. This is the idea of the meta-circular interpreter, consisting of two functions:

These functions evaluate a program in a mutually recursive fashion.

This, too, is one of the most beautiful ideas in computing, as well as the mechanism and inspiration for modern-day interpreters and compilers.

Though McCarthy created Lisp, he did not implement the first Lisp interpreter. McCarthy developed Lisp as a theoretical exercise: an attempt to create a programming alternative to the Turing Machine using Alonzo Church's lambda calculus.

Steve Russell, one of McCarthy's graduate students, suggested that he could implement the theory in an IBM 704 machine language program. McCarthy laughed and told him, "You're confusing theory with practice...". Russell did it any way.

Thanks to Russell and the IBM 704, we also have the functions named car and cdr — as well as what is considered to be the first video game ever created!

McCarthy and Russell soon discovered that Lisp was more powerful than the language that they had planned to build as part of their theoretical exercise, and the history of computing was forever changed.

The syntax and semantics of Lisp programs are so sparse and so uniform that the McCarthy's universal Lisp interpreter consisted of about one page of Lisp code. Here it is, on Page 13 of the the Lisp 1.5 Programmer's Manual, published in 1962. (The permanent online home of the manual is at softwarepreservation.org.)

Here is Page 13:

an image of Page 13 of the Lisp 1.5 user's manual, which contains the definition of the Lisp interpreter in Lisp
Page 13 of the Lisp 1.5 Programmer's Manual

But this is a computer program. Why settle for a JPG image from a 60-year-old technical report?

We are programmers, the dreamers of dreams!

So I implemented this universal Lisp interpreter in Racket. It is the file universal-lisp-interp.rkt in today's zip file.

Let's study it for a few minutes...

Now do you understand why syntax procedures are so important?

It is remarkable how much can be built out of so little.

Alan Kay, the creator of modern object-oriented programming, often compares McCarthy's universal Lisp interpreter to Maxwell's equations in physics: a small, simple set of equations that capture a huge amount of understanding and enable a new way of thinking.

I sometimes think of the components of this program as the basic particles out of which all computation is built, akin to the atomic theory of matter. Out of these few primitives, all programs can be built.

I know this probably excites me more than you. But we are still so close to our history. John McCarthy died in October 2011, during a previous offering of this course. Steve Russell is still alive. Unlike other sciences, computer science is still young, and many of its creators are still with us. What a gift.

As Paul Graham writes:

It's hard for us now to understand what a conceptual leap that was at the time. Paradoxically, one of the reasons his achievement is hard to appreciate is that it was so successful. Practically every programming language invented in the last 20 years [now 30+] includes ideas from Lisp, and each year the median language gets more Lisplike.

We see the original DNA of McCarthy's ideas and Russell's code in the tools we use today. This interpreter is at the base of Racket, Scheme, Common Lisp, Clojure, Dylan, and many other languages — but it is also fundamentally the core of every language you use. Don't miss the opportunity to appreciate big ideas, or where computer science comes from.

But this isn't just archeology; the same ideas drive language design and implementation today. That means they also drive the programming you do today. Consider this white paper that made the rounds a few years ago. A new syntactic abstraction in Java may be coming your way soon...

a screenshot of the SuperCollider programming environment
SuperCollider in action

In the end, the duality of program and data, and the idea of language that bridges the gap between the two, make all programming possible. Even something as ambitious as SuperCollider, a programming environment for real time audio synthesis and algorithmic composition. It's just a language, with an interpreter that process programs written in it. Created by people just like you and me.

If you want to play with Forth or Joy, or experiment with different ways to pass parameters, or invent a new language that will change the world, you can do this, too.

This is, in a very real way, a rather long answer to a common question from students: Why Racket?

If you'd like to read more about the history and importance of McCarthy's Lisp, check out Paul Graham's essay, The Roots of Lisp.

John McCarthy did much more than create Lisp.

I first learned about McCarthy not from Lisp but from my first love, AI. McCarthy coined the term "Artificial Intelligence" when organizing (along with Minsky, Rochester, and Shannon) the 1956 Dartmouth workshop that gave birth to the field.

I studied McCarthy's work in AI using the language he had created. To me, he was a giant of AI long before I recognized that he was giant of programming languages, too.

Like many pioneers of our field, he laid the groundwork in many subdisciplines. They had no choice; they had to build their work out of ideas using only the rawest materials.

McCarthy is even credited with the first public descriptions of time-sharing systems and what we now call cloud computing. For McCarthy's 1970-era predictions about home computers and the cloud, see his paper The Home Information Terminal, reprinted in 2000.

The Big Ideas

My thoughts about the most important ideas we study in this course change from semester to semester. Here is a list of five for 2023:

The Future: The Final Exam

The final is cumulative, with an emphasis on material since Quiz 3: on data abstractions, your interpreter, and our "Bringing It All Together" sessions. It will look like our first three exams: a mix of short-answer questions and programming exercises, with perhaps a few even-shorter-answer questions.

Since Quiz 3, we have studied a few ideas:

The cumulative parts of the exam will be much like Quizzes 1-3. Among the important topics on the exam are:

Wrap Up