We have identified in
Lisp
Python
some of the elements that must appear in any powerful programming language:
-
Numbers and arithmetic operations are primitive data and
procedures.
functions.
-
Nesting of combinations provides a means of combining operations.
-
Declaration assignments that associate names with values provide a
limited means of abstraction.
Now we will learn about
procedure definitions,
function definitions,
a much more powerful abstraction technique by which a compound
operation can be given a name and then referred to as a unit.
We begin by examining how to express the idea of
squaring.
We might say,
To square something, multiply it by itself.
To square something, take it times itself.
This is expressed in our language as
| Original |
Python |
|
(define (square x) (* x x))
|
def square(x): return x * x
|
We can understand this in the following way:
| Original |
Python |
|
(define (square x) (* x x))
;; ^ ^ ^ ^ ^ ^
;; To square something, multiply it by itself.
|
def square( x ): return x * x
# ^ ^ ^ ^ ^ ^ ^
# To square something, take it times itself.
|
We have here a
compound procedure,
compound function,
which has been given the name square. The
procedure
function
represents the operation of multiplying something by itself. The 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
definition
creates this compound
procedure
function
and associates it with the name
square.
The general form of a procedure definition
The simplest form of a function definition
is
| Original |
Python |
|
(define ($\langle \textit{name} \rangle$ $\langle\textit{formal parameters}\rangle$) $\langle \textit{body} \rangle$)
|
def $name$($parameters$): return $expression$
|
The
$\langle \textit{name}\rangle$
$name$
is a symbol to be associated with the
procedure
function
definition in the environment.
The
$\langle \textit{formal parameters}\rangle$
$parameters$
are the names used within the body of the
procedure
function
to refer to the
corresponding arguments of the
procedure.
function.
| Original |
|
Python |
|
The
$\langle \textit{body} \rangle$
is an expression
that will yield the value of
the procedure
application when the formal parameters are replaced by
the actual arguments to which the
procedure
is applied.
The $\langle \textit{name} \rangle$
and the
$\langle \textit{formal parameters} \rangle$
are grouped within
parentheses, just as they would be in an actual call to the procedure
being defined.
|
|
The word def is a keyword in Python. Keywords carry a particular meaning, and
thus cannot be used as names. A keyword in a program component instructs the Python
interpreter to treat the component as a syntactic form
with its own evaluation rule.
The $parameters$
are grouped within
parentheses and separated by commas, as they will be in an application
of the function being defined.
In the simplest form, the
body of a function definition is a single
return statement,
which consists of the keyword
return
followed by the return expression
that will yield the value of the function application, when the
formal
parameters are replaced by the actual arguments to which the function
is applied.
|
| Original |
|
Python |
|
Having defined square,
we can now use it:
|
|
Having defined square,
we can now use it in a
function application expression:
|
| Original |
Python |
|
(square 21)
441
|
square(21)
|
| Original |
|
Python |
|
|
|
Function applications are—after operator
combinations—the second kind of combination of
expressions into larger expressions that we encounter.
The general form of a function application is
$function$-$expression$($argument$-$expressions$)
where the
$function$-$expression$
of the application specifies
the function to be applied to the comma-separated
$argument$-$expressions$.
To evaluate a function application, the interpreter follows
a procedure
quite similar to the procedure for operator combinations described in
section [1.1.3].
- To evaluate a function application, do the following:
-
Evaluate the subexpressions of the application, namely
the function expression and the argument expressions.
-
Apply the function that is the value of the function expression
to the values of the argument expressions.
The same procedure applies to applications of the primitive function
print that we encountered already in
section [1.1.1].
|
| Original |
Python |
|
(square (+ 2 5))
49
|
print(square(2 + 5))
49
|
| Original |
|
Python |
| |
|
Here, the argument expression of print
is a compound expression, the application expression
square(2 + 5), whose argument expression
is itself a compound expression,
the operator combination 2 + 5.
|
| Original |
Python |
|
(square (square 3))
81
|
print(square(square(3)))
81
|
| Original |
|
Python |
| |
|
Of course function application expressions can be further nested.
|
We can also use square
as a building block in defining other
procedures.
functions.
For example, $x^2 +y^2$ can be expressed as
| Original |
Python |
|
(+ (square x) (square y))
|
square(x) + square(y)
|
We can easily
define
define
a
procedure
sum-of-squares
function
sum_of_squares
that, given any two numbers as arguments, produces the
sum of their squares:
| Original |
Python |
|
(define (sum-of-squares x y)
(+ (square x) (square y)))
(sum-of-squares 3 4)
|
def sum_of_squares(x, y):
return square(x) + square(y)
|
| Original |
|
Python |
| |
|
For readability, we can start a new line after the colon,
in which case the function body needs to be indented.
|
| Original |
Python |
|
(sum-of-squares 3 4)
25
|
print(sum_of_squares(3, 4))
25
|
Now we can use
sum-of-squares
sum_of_squares
as a building block in constructing further
procedures:
functions:
| Original |
Python |
|
(define (f a)
(sum-of-squares (+ a 1) (* a 2)))
|
def f(a):
return sum_of_squares(a + 1, a * 2)
|
| Original |
Python |
|
(f 5)
136
|
print(f(5))
136
|
| Original |
|
Python |
|
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 interpreter, like + and
*,
or defined as a compound procedure.
|
|
In addition to compound functions, any Python environment provides
primitive functions that are built into the interpreter or loaded
from libraries.
Besides the primitive functions provided by the operators
and the primitive function print,
the Python environment used in this book includes
additional primitive functions
such as the function
math_log,
which computes the natural logarithm of its argument.
These additional primitive functions are used in exactly the same way as
compound functions; evaluating the application
print(math_log(1)) results in the display of the number 0.0.
Indeed, one could not tell by looking at the definition of
sum_of_squares given above whether
square was built into the
interpreter, loaded from a library, or defined as a compound function.
|
1.1.4
Compound Procedures
Functions