Composition of Functions
Building Functions for Programs
Recall:
1) Modular programming enourages us to conceal much of what a function call does internally; this prevents unpredictable interactions. We know what kind of input the function will take--this is the domain of the function--and what kind of output, if any, the function will return--this is the co-domain or range.
2) In any programming environment that uses functions such as C, C++, or Java, the code of any function can call another function. This encourages writing short code for functions which in turn will call other functions. Let f be a function which might call another function g inside of its code. And let us assume these functions return values and g returns a value which is passed to f, that is, the value that g returns is in the domain of f. This is a composition of f with g. Think of f and g as machines that take inputs, process such inputs, and then return something. Look at the picture on page 431 at the start of Section 7.4 in your text. g returns a datatype that is in the domain of f, so f can process it.
An Example using just Times and Plus:
Let us say we wish to interpret some mathematical expression like x (y + z) functionally; assume x, y, and z are of type integer. The Plus machine needs an input of two numbers, as does the Times machine. Functionally, we will write the Plus[y,z], a function of two variables, for y + z, and the Times machine, also a function of two variables which multiplies two values, we would have Times[x, Plus[y,z]] as a functional representation for x(y + z). Notice this is a function of three variables, x, y, z. Now write f(x,y,z) as notation for that function with values x, y, and z, and we have f(x,y,z) with code that first calls Plus[y,z] which might return a value we temporarily call r, and then it calls the Times function for x, and r, that is, Times[x, r] and returns this value.
Let us actually define and execute such a function f.
f[x_Integer, y_Integer, z_Integer] := Times[x, Plus[y,z]]
This is now a routine stored in computer memory. We see it is a composite function because one of the values of the Times routine is a value that is called by another routine, the Plus routine. Note the underscores for the variables on the left side. This indicates they are DUMMY variables. The variables on the right side will be interior and private variables used in the routine itself. For example, when you write f[5,2, 3], 5 , 2, and 3 will be passed to the temporary storage locations named by the variables x, y, and z. Let us actually execute this function for those values:
f[5,2,3]
Our function produces 25, no surprise. Please note that this notation is prefix notation. We can write the expression in ordinary infix notation (the plus and times between the values) and we get:
5*(2 + 3)
The point to all of this is that the idea is the same. Following the rules of using the parenthesis, we first evaluate what is inside the innermost parenthesis, working outwards, which gives us 5, then we perform the multiplication. Notice that the parenthesis a function to be called inside of the Times routine. Let us try some functions of functions of functions like . . . (notice since Times and Plus are BINARY operations (that is, they take exactly two arguments), we are careful with our parentheses.
5*(3 + 4*(3 +(2 +7*(3 + 4))))
And in prefix notation, this would be:
Times[5, Plus[3, Times[4, Plus[3, Plus[2, Times[7, Plus[3,4]]]]]]]
Well, with 4 parentheses deep, we could easily get confused even with working with ordinary infix notation. Do you see the heirarchy here? The innermost machine or function call is a Plus, then Times, Plus, Plus, Times, Plus, and finally the outermost machine is Times. Each machine needs two inputs. The machines are linked together in exactly that order. This is an expression involving 8 variables: a*(b + c*(d + (e + f *(g + h)))), so thinking of this as a composite function, the input must provide 8 real numbers input in a precise order. When a computer reads, or parses such expressions, it does so exactly as we would do it, namely, starting from the innermost parenthesis and working out.
The heiarchy of function calls can be very deep and very complex. Such things are examples of a structure called a tree, and they are important enough to be studied on their own. We will study trees Chapter 11. This will help us visualize and program what the compiler must do to parse such expressions. You might want to look at a parsing tree for English sentences. Take a look at Example 11.5.3. But look at a parsing tree for mathematical expressions in Example 11.5.10. Climbing up from the bottom of the tree is starting the evaluation from the innermost expressions and working upwards.
The use of parentheses is an artifact of the infix or postfix notation. Any who have used an HP hand calculator that uses so-called Polish notation knows that expressions can be written without parentheses; but despite this, the tree-structure of the expression is the same.
The composition of functions of a single variable have a special notation. f composition g, that is you do g, passing values to f which in turn does f with a final result is written as fog, with a small circle slightly raised between the two functions. Notice that in general the order you write this is VERY important.
Inverse Functions
Consider once more that functions perform actions. Can you undo what a function does? If you can, this would be called the inverse of the function. Take for example the squaring function (on page 392) which Ms. Epp calles here f. The question is, if you are given the square of a real number, can you find the original number that gave you that square number? No. If I hand you 4, telling you it is the square of a certain number, can you tell me the number? No. It could be either -2 or +2. You cannot undo the operation of squaring.
HOWEVER, if the domain of the function is defined to be the NON-NEGATIVE numbers, and the co-domain to be also all non-negative numbers, then indeed any squaring operation performed on a number can be undone. The name of the inverse of the squaring function is the square root function. Your text and Module make clear the conditions when you can have an inverse. It must be one-to-one and be onto. The expression for the inverse of a function called f is peculiar and can be confusing. One places a superscript -1 to the right of the function. So the inverse of f is written:
. This is NOT an exponent. Think of this as a single expression. Naturally, if you do f to some object, call it X, then undo what you did, you get back X. In other words, the COMPOSITION of a function with its inverse is a function which leaves everything the same. A function that leaves everything the same is called the identity function. The identity function of the real numbers to the real numbers is just f(x) = x, and its graph is the 45 degree line passing upwards through the origin from left to right.
| Created by Mathematica (October 24, 2006) |