Structure and Interpretation of Computer Programs 1.1.4
Compound Procedures
We clarified in the beginning that there indeed was 3 things that one should keep i mind when discussing a programming language.
- Primitive expressions, there barebones that a computer understands, this may be numbers and arithmetic operations such as 4,3,5 or +,*,/
- Means of combination, how you can combine these procedures ie a means of combining operators and operands. ie (+ (- 4 3) (+ 0.5 0.5))
- Means of Abstraction: Definitions that associate names with values provides a limited means of abstraction (define fsix (+ 1 1 2 3 5 7))
Now we go onto procedure definitions. A means of defining procedures through a compound operation that is given a name and then referred to as a unit. A simple procedure definition can be seen below.
(define (square x) (* x x ) )
As we can see as opposed to defining a single name like “fsix” we are defining a compound operation “square x”, and x is then referred to in the definition as a unit just like it would be if it was a number.
Compound procedures follow this formula to be created
(define (<name> <formal parameters>) (<body>) )
The <name> is the name that the interpreter of lisp will know to call the following procedure, the <formal parameters> are the names that will be referred to within the body as units, the <body> containts the expression or combined expression using the formal parameters as units.
To see a slightly more complicated example of this say for instance I wanted to find the sum of the squares of any two numbers. That would be defined as a compound procedure like so .
(define (sum-of-squares x y ) (+ (square x) (square y)) )
Here you can start to see the values of incremental development with lisp and how you can even begin to manipulate programs as data. Here we passed the “square” compound procedure into the definition of the sum of squares. How about we want to make a function that takes 1 number then adds the squares of that number + 10 and that number * 20 . We will call the compound procedure “f”
(define (f x) ( sum-of-squares (+x 10) (* y 20) )
Here we can see that we have in fact made a compound procedure that first adds up two compound procedures with compound expressions as arguments.
So how does this get evaluated you may be asking. Well to evaluate the <body> of argument you replace the <functional parameters> replaced by the corresponding argument .
Thus f(5) yields ( sum-of-squares (+ 5 10 ) (* 5 20))
Operand 1 and 2 are (+ 5 10) and (* 5 20 ) respectively , we must evaluate these for the procedure to be applied, which equate to 15 and 100.
Then we must apply the sum-of-squares procedure to these operands which means that (sum-of-squares 15 100) then substitutes with (+ (square 15) (square 100) ) .
Afterwards it uses the same evaluation rule to apply the “square” procedure within the two operands. so that this then substitutes to
(+ (* 15 15) (* 100 100) )
Now this is simply back to Rule 1 of the evaluation, where we must evaluate all subexpressions first . This then results in
(+ 225 10000)
….
10225
As you might see the compound procedures are evaluated just the same as primitive procedures , it simply substitutes the <formal parameters> with the corresponding units in the <body> of the procedure as the rules to define the compound procedure. We can assume that primitive procedures are built into the interpreter as Machine Instructions.
This process is known as a substitution model where we substitute (square 15) for (* 15 15) etc or more specifically we substitute the formal parameters for the values that are in the body. ie the 15 is substituted as the (* x x) in square, So we
So the substitution model is not a description of how the interpreter works but more of a helper as to how think about the procedure as it substitutes deeper and deeper in.