Application Center - Maplesoft

App Preview:

Maple Programming: 2.7: Evaluating function calls

You can switch back to the summary page by clicking here.

Learn about Maple
Download Application


 

2.07.mws

Programming in Maple

Roger Kraft
Department of Mathematics, Computer Science, and Statistics
Purdue University Calumet

roger@calumet.purdue.edu

2.7. Evaluating function calls

If f  is the name of a Maple function (so f  was defined using the arrow operator), then an expression of the form

f( any-maple-expression )

 is called a function call. Here is an example of a function and several function calls.

>    f := x -> x^2-1;

f := proc (x) options operator, arrow; x^2-1 end proc

>    f(2);

3

>    f(w);

w^2-1

>    f(u);

u^2-1

>    f(w+u);

(w+u)^2-1

>    f( (1+cos(Pi/4))/12 );

(1/12+1/24*2^(1/2))^2-1

>    f( f(u) );

(u^2-1)^2-1

In this section we will see how Maple evaluates a function call. To get a sense of what it is we want to know, consider the following example of a function call.

>    z := 4;

z := 4

>    f(z);

15

What did Maple do exactly? Did it plug z  into f  and get z^2-1  and then evaluate the z  to get 4 so it had 4^2-1=15. Or did Maple evaluate z  first to get 4, then plug 4 into f  to get 4^2-1=15? As we will see shortly, the difference between these two orders of evaluation is important and we should know which one Maple uses. (In short, Maple uses the later of the two orders.)

>   

There are two parts to a function call, f(w) . There is the name of the function, in this case f , and there are the operands of the function, in this case w . There are three steps to evaluating a function call. First Maples evaluates the operand (or operands if it is a multivariate function). Then Maple evaluates the name of the function to get the function's definition. Then Maple plugs the results from evaluating the operands into the function's definition and computes the value of the function. (Note: When Maple evaluates the operands it can use either full evaluation or last name evaluation, depending on the operands.)

>   

Here are some more examples.

>    f := 'g';

f := g

>    g := x -> x^3;

g := proc (x) options operator, arrow; x^3 end proc

>    z := 2;

z := 2

>    f(z);

8

In the last function call, first the z  was evaluated to 2, then the f  was evaluated to g  and g  was evaluated to the cubing function, then the cubing function was applied to 2 to get 8.

>   

Now let us wipe out the definition of g  and try the function call f(z)  again.

>    g := 'g';

g := 'g'

>    f(z);

g(2)

Once again z  was evaluated to 2 and f  was evaluated to g , but g  does not evaluate to anything now. So the result for f(z)  was g(2) . We call g(2)  an unevaluated function call . We get unevaluated function calls whenever an unassigned variable is used as a function name in a function call. One of the most common ways to get un unevaluated function call as a result is to misspell the name of a Maple command.

>    factir( 'x^2+2*x+1' );

factir(x^2+2*x+1)

>   

Here is a quirk in Maple's function call evaluation. If we call a function with more operands than its definition specifies, then Maple just ignores the extra operands. (In a later chapter we will see why Maple does this.)

>    f := (x,y) -> x+y;

f := proc (x, y) options operator, arrow; x+y end proc

>    f(2,3,4);

5

But if we call a function with fewer operands than its definition specifies, then we get an error message.

>    f(2);

Error, (in f) f uses a 2nd argument, y, which is missing

>   

Here is an example where we can really see that Maple evaluates a function's operands before evaluating the function. Here is a multivariate function f .

>    f := (x,y) -> x-y;

f := proc (x, y) options operator, arrow; x-y end proc

Now we shall define a function that is a bit unusual. The rand  function, which is built into Maple, is a function that takes no arguments and returns a random integer. Let us define a function g  that makes use of rand  like this.

>    g := x -> rand();

g := proc (x) options operator, arrow; rand() end proc

So g  is a function that takes in one number and outputs a randomly chosen integer (that does not depend in any way on the input number!). Now consider the function call f(g(0),g(0)) . If Maple took the arguments and plugged them directly into the definition of f , Maple would get g(0)-g(0) , which is zero (see the next command), so the value of the function call would be zero.

>    g(0)-g(0);

0

But if Maple evaluates the operands to f  first, then Maple will evaluate f  with two randomly chosen integers, so the value of the function call will be non zero (with probability very  close to 1).

>    f(g(0),g(0));

106308975811

Every time you execute this function call you will get a different value. (Try it.) This example shows that the order that Maple uses for evaluating a function call is important since, in some circumstances, the order of evaluation can determine the value of the function call.

>   

You may at this point have a question about why g(0)-g(0)  should be zero. Algebraically that seems reasonable. But if Maple used full evaluation and evaluated both of the g(0)  terms before doing the subtraction, then g(0)-g(0)  would not be zero. What Maple did with g(0)-g(0)  was apply one of its automatic simplification rules . Whenever Maple has the same expression on either side of a minus sign, it automatically simplifies this to zero (without evaluating the expressions). Maple has many other automatic simplification rules. These are not the same as evaluation rules but as we have just seen, an automatic simplification rule can influence how Maple finds the value of an expression. Here is another example.

>    h := x -> x^2;

h := proc (x) options operator, arrow; x^2 end proc

>    h(g(0)/g(0));

1

If it were not for an automatic simplification rule (anything divided by itself is 1), Maple would have evaluated this last expression differently (the automatic simplification rule in this case was applied before Maple evaluated the operand in the function call). Most of Maple's automatic simplification rules are pretty obvious, but unfortunately there does not seem to be any documentation about them in Maple's online help system.

>   

Here is another way to see that Maple evaluates the operands of a function call before applying the function. We can use delayed evaluation to prevent Maple from making the function call.

>    'f'(g(0),g(0));

f(343633073697,474256143563)

The right-quotes around f  prevent Maple from evaluating the name f  to the function (x,y)->x-y  so Maple is not able to actually complete the function call. But nothing prevented Maple from evaluating the operands of the function call, and so we see that Maple evaluates the operands before it tries to apply the function.

This last example is actually a very useful trick for figuring out what is sometimes going on with Maple. When we get an error message from Maple or a command does not do what we expect it to do, it can sometimes be useful to delay the evaluation of a Maple command to see what were the exact operands that the command was working with. This may help explain the cause of the error message or why the command did what it did. Here is an example. Give x  a value.

>    x := 5;

x := 5

We know that the following command causes an error message.

>    plot( x^2, x=-2..2 );

Error, (in plot) invalid arguments

By delaying evaluation of the name plot , we can get more information about what went wrong in the above command.

>    'plot'( x^2, x=-2..2 );

plot(25,5 = -2 .. 2)

And of course we see that 5 running from -2 to 2 is what does not make sense.

>   

Exercise : Explain the following sequence of commands.

>    f := x -> x^2;

f := proc (x) options operator, arrow; x^2 end proc

>    z := 5;

z := 5

>    f('z');

z^2

>    'f'(z);

f(5)

>    'f(z)';

f(z)

>   

>   

>