Let's make a list of primitive operators.
I threw gcd in there too even though it's not a primitive operator because remember that there's no distinction between built-in functions and the ones that we make.
What do you think happens if I type
Well let's use the substitution rule to figure out what's happening. (car procedures) evaluates to +, right? So now it's just (+ 3 4). That's why we had two sets of parentheses at the start. One to evoke car, and one to evoke whatever car returns. So we get 7.
scheme@(guile-user)> ((cadr procedures) 3 4)
$2 = -1
scheme@(guile-user)> ((caddr procedures) 3 4)
$3 = 1
scheme@(guile-user)> ((cadddr procedures) 3 4)
$4 = 12
scheme@(guile-user)> ((cddddr procedures) 3 4)
ERROR: Wrong type to apply: (#<procedure / (#:optional _ _ . _)>)
Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.
scheme@(guile-user) [1]> ,q
scheme@(guile-user)> ((car (cddddr procedures)) 3 4)
$5 = 3/4
Okay so what's this error and why did it happen? Why didn't get cddddr get me the 5th element in the list the way caddr got me the 4th element? Remember, car gets the first item, and cdr gets the rest, cadr gets the second and the cddr gets the rest. Let's draw another box diagram.
+---+---+ +---+---+ +---+---+ +---+---+ +---+---+ | | -|-->| | -|-->| | -|-->| | -|-->| | / | +_|_+___+ +_|_+___+ +_|_+___+ +_|_+___+ +_|_+___+ | | | | | \ / \ / \ / \ / \ / . . . . . + - gcd * /
cddddr doesn't get us / it gets us the pair (cons / '()). This '() is a list terminator, the null list, and it's getting in the way of our decision. That's why we need the car of the cddddr.
But look at this magical thing we have here, we can call a named procedure, +, or whatever, without actually using the name of the function, because + is ~really~ just a pointer to the real procedure. and (car is also returning a pointer to the procedure, so ((car follows that pointer and evaluates that procedure. This is really exciting.