(03 - 3) Lectura I - FP
(03 - 3) Lectura I - FP
(03 - 3) Lectura I - FP
6
will see that these same rules allow us to build procedures to manipulate
compound data as well.
1.1.1 Expressions
One easy way to get started at programming is to examine some typical
interactions with an interpreter for the Scheme dialect of Lisp. Imagine
that you are siing at a computer terminal. You type an expression, and
the interpreter responds by displaying the result of its evaluating that
expression.
One kind of primitive expression you might type is a number. (More
precisely, the expression that you type consists of the numerals that
represent the number in base 10.) If you present Lisp with a number
486
gramming language. Some typical issues involved are these: Some computer systems
distinguish integers, such as 2, from real numbers, such as 2.71. Is the real number 2.00
different from the integer 2? Are the arithmetic operations used for integers the same
as the operations used for real numbers? Does 6 divided by 2 produce 3, or 3.0? How
large a number can we represent? How many decimal places of accuracy can we repre-
sent? Is the range of integers the same as the range of real numbers? Above and beyond
these questions, of course, lies a collection of issues concerning roundoff and trunca-
tion errors—the entire science of numerical analysis. Since our focus in this book is on
large-scale program design rather than on numerical techniques, we are going to ignore
these problems. e numerical examples in this chapter will exhibit the usual roundoff
behavior that one observes when using arithmetic operations that preserve a limited
number of decimal places of accuracy in noninteger operations.
5
roughout this book, when we wish to emphasize the distinction between the
input typed by the user and the response printed by the interpreter, we will show the
laer in slanted characters.
7
Expressions representing numbers may be combined with an expres-
sion representing a primitive procedure (such as + or *) to form a com-
pound expression that represents the application of the procedure to
those numbers. For example:
(+ 137 349)
486
(- 1000 334)
666
(* 5 99)
495
(/ 10 5)
2
(+ 2.7 10)
12.7
8
(+ 21 35 12 7)
75
(* 25 4 12)
1200
No ambiguity can arise, because the operator is always the lemost el-
ement and the entire combination is delimited by the parentheses.
A second advantage of prefix notation is that it extends in a straight-
forward way to allow combinations to be nested, that is, to have combi-
nations whose elements are themselves combinations:
(+ (* 3 5) (- 10 6))
19
ere is no limit (in principle) to the depth of such nesting and to the
overall complexity of the expressions that the Lisp interpreter can eval-
uate. It is we humans who get confused by still relatively simple expres-
sions such as
(+ (* 3 (+ (* 2 4) (+ 3 5))) (+ (- 10 7) 6))
which the interpreter would readily evaluate to be 57. We can help our-
selves by writing such an expression in the form
(+ (* 3
(+ (* 2 4)
(+ 3 5)))
(+ (- 10 7)
6))
9
expression.6
Even with complex expressions, the interpreter always operates in
the same basic cycle: It reads an expression from the terminal, evaluates
the expression, and prints the result. is mode of operation is oen
expressed by saying that the interpreter runs in a read-eval-print loop.
Observe in particular that it is not necessary to explicitly instruct the
interpreter to print the value of the expression.7
causes the interpreter to associate the value 2 with the name size.8
Once the name size has been associated with the number 2, we can
refer to the value 2 by name:
size
2
6
Lisp systems typically provide features to aid the user in formaing expressions.
Two especially useful features are one that automatically indents to the proper prey-
print position whenever a new line is started and one that highlights the matching le
parenthesis whenever a right parenthesis is typed.
7
Lisp obeys the convention that every expression has a value. is convention, to-
gether with the old reputation of Lisp as an inefficient language, is the source of the
quip by Alan Perlis (paraphrasing Oscar Wilde) that “Lisp programmers know the value
of everything but the cost of nothing.”
8
In this book, we do not show the interpreter’s response to evaluating definitions,
since this is highly implementation-dependent.
10
(* 5 size)
10
11
of different environments).9
Even this simple rule illustrates some important points about processes
in general. First, observe that the first step dictates that in order to ac-
complish the evaluation process for a combination we must first per-
form the evaluation process on each element of the combination. us,
the evaluation rule is recursive in nature; that is, it includes, as one of
its steps, the need to invoke the rule itself.10
Notice how succinctly the idea of recursion can be used to express
what, in the case of a deeply nested combination, would otherwise be
viewed as a rather complicated process. For example, evaluating
9
Chapter 3 will show that this notion of environment is crucial, both for under-
standing how the interpreter works and for implementing interpreters.
10
It may seem strange that the evaluation rule says, as part of the first step, that
we should evaluate the lemost element of a combination, since at this point that can
only be an operator such as + or * representing a built-in primitive procedure such as
addition or multiplication. We will see later that it is useful to be able to work with
combinations whose operators are themselves compound expressions.
12
390
* 26 15
+ 2 24
+ 3 5 7
* 4 6
(* (+ 2 (* 4 6))
(+ 3 5 7))
13
take care of the primitive cases by stipulating that
• the values of other names are the objects associated with those
names in the environment.
We may regard the second rule as a special case of the third one by stip-
ulating that symbols such as + and * are also included in the global envi-
ronment, and are associated with the sequences of machine instructions
that are their “values.” e key point to notice is the role of the environ-
ment in determining the meaning of the symbols in expressions. In an
interactive language such as Lisp, it is meaningless to speak of the value
of an expression such as (+ x 1) without specifying any information
about the environment that would provide a meaning for the symbol
x (or even for the symbol +). As we shall see in Chapter 3, the general
notion of the environment as providing a context in which evaluation
takes place will play an important role in our understanding of program
execution.
Notice that the evaluation rule given above does not handle defini-
tions. For instance, evaluating (define x 3) does not apply define to
two arguments, one of which is the value of the symbol x and the other
of which is 3, since the purpose of the define is precisely to associate x
with a value. (at is, (define x 3) is not a combination.)
Such exceptions to the general evaluation rule are called special forms.
define is the only example of a special form that we have seen so far,
but we will meet others shortly. Each special form has its own evalu-
ation rule. e various kinds of expressions (each with its associated
14
evaluation rule) constitute the syntax of the programming language. In
comparison with most other programming languages, Lisp has a very
simple syntax; that is, the evaluation rule for expressions can be de-
scribed by a simple general rule together with specialized rules for a
small number of special forms.11
15
We begin by examining how to express the idea of “squaring.” We
might say, “To square something, multiply it by itself.” is is expressed
in our language as
(define (square x) (* x x))
We have here a compound procedure, which has been given the name
square. e procedure represents the operation of multiplying some-
thing by itself. e thing to be multiplied is given a local name, x, which
plays the same role that a pronoun plays in natural language. Evaluating
the definition creates this compound procedure and associates it with
the name square.12
e general form of a procedure definition is
(define (⟨name⟩ ⟨formal parameters⟩)
⟨ body⟩)
e ⟨name ⟩ is a symbol to be associated with the procedure definition in
the environment.13 e ⟨formal parameters ⟩ are the names used within
the body of the procedure to refer to the corresponding arguments of
the procedure. e ⟨body ⟩ is an expression that will yield the value of
12
Observe that there are two different operations being combined here: we are creat-
ing the procedure, and we are giving it the name square. It is possible, indeed important,
to be able to separate these two notions—to create procedures without naming them,
and to give names to procedures that have already been created. We will see how to do
this in Section 1.3.2.
13 roughout this book, we will describe the general syntax of expressions by using
italic symbols delimited by angle brackets—e.g., ⟨name ⟩—to denote the “slots” in the
expression to be filled in when such an expression is actually used.
16
the procedure application when the formal parameters are replaced by
the actual arguments to which the procedure is applied.14 e ⟨name ⟩
and the ⟨formal parameters ⟩ are grouped within parentheses, just as they
would be in an actual call to the procedure being defined.
Having defined square, we can now use it:
(square 21)
441
(square (+ 2 5))
49
(square (square 3))
81
14 More generally, the body of the procedure can be a sequence of expressions. In this
case, the interpreter evaluates each expression in the sequence in turn and returns the
value of the final expression as the value of the procedure application.
17
Compound procedures are used in exactly the same way as primitive
procedures. Indeed, one could not tell by looking at the definition of
sum-of-squares given above whether square was built into the inter-
preter, like + and *, or defined as a compound procedure.
18