Breaking Down Compound Procedures in Lisp
With a sprinkle of JavaScript
I’ve been working my way through the first chapter of Structure and Interpretation of Computer Programs. I find it helpful to take it slow and write about what I’m learning so it sinks in more deeply.
I also watched the first lecture on MIT’s OpenCourseWare YouTube channel. (You can really tell Harold Abelson is in his element.)
At section 1.1.4 on Compound Procedures I wanted to step back and break it down a little for myself.
Also, since my coding experience started more or less with JavaScript, I thought it would be interesting to work out what he’s teaching both in Lisp and JavaScript, to better understand the underlying concepts. Earlier he mentioned that one of the benefits of using Lisp is that it has “almost no syntactic structure.” So I find it helpful to compare the two languages to get a better grip on what is syntactically unique to JavaScript.
He mentions that any powerful programming language must contain three elements:
- Primitive objects or expressions: These would be “the simplest entities the language is concerned with,” like numbers and arithmetic operations (
+, —, /, *
) - Means of combination: The way we combine those primitive objects, or the method “by which compound elements are built from simpler ones.”
- Means of abstraction: I take this to mean a way of building on smaller elements of programming to build larger, more complex programs. In other words, using smaller building blocks to make bigger ones.
In the Compound Procedures section, he talks about a way to do this third thing. He starts by defining a procedure for squaring something.
(define (square x) (* x x))
I find his way of writing this out to be very helpful:
(define (square x) (* x x))
To square something, multiply it by itself.
In JavaScript this would look like:
function square(x) {
return x * x;
}
In order to build on this, he takes that first procedure (square
) and plugs it into another procedure called sum-of-squares
.
(define (sum-of-squares x y)
(+ (square x) (square y)))
- He defines the procedure:
sum-of-squares
- Tells it which parameters will go into it:
x y
- And then what will happen when he invokes the
sum-of-squares
procedure:(+ (square x) (square y))
In other words, take the square of each and then add them together.
In JavaScript:
function sumOfSquares(x, y) {
return square(x) + square(y);
}
From here he uses the sum-of-squares
building block to build yet another procedure called f
:
(define (f a)
(sum-of-squares (+ a 1) (* a 2)))
- Define the procedure:
f
- Give it a parameter:
a
- Then run the
sum-of-squares
procedure ona
as follows:((+ a 1) (* a 2))
So, for example, running (f 5)
in your Lisp interpreter will return 136
.
// Feed in the number 5:
(sum-of-squares (+ 5 1) (* 5 2))// Before squaring:
(sum-of-squares (6) (10))// After squaring:
(sum-of-squares (36) (100))// After running the sum-of-squares procedure and "summing" them:
136
In JavaScript:
function f(a) {
return square(a + 1) + square(a * 2);
}