Copyright (C) 1997 Rich Neidinger, John Swallow, and Todd Will.  Free for
distribution to college and university instructors for personal,
non-commercial use.  If these notebooks are used in a course, the authors
request $20 per student.

3. Defining Variables and Functions

Last revision:  August 25 1996

In this section we cover various ways to store a value or an expression in
a variable (a place inside the computer) as well as ways to store a list of
instructions inside a function.

Variable Declaration and Initialization: Set

We have already learned how to give a value a name: we decide on a
consecutive sequence of letters (the "name"), follow it by a single equals
sign, and then place the value on the right.  Let's consider this operation
in a little more detail.  When we give Mathematica an instruction such as
"mess = 7", Mathematica does several things.  First, Mathematica evaluates
the right-hand side of the expression (yielding an Integer, 7).  Then
Mathematica declares a new variable (by which we mean that Mathematica will
remember from now on that a certain name is significant), named "mess".
Then Mathematica assigns this variable an initial value, the Integer 7.
Finally, the result of our operation is whatever value was assigned, in
this case 7, so Mathematica gives us a 7 back (in our Output cell).  From
now on (unless we change "mess"), any time we use "mess", Mathematica will
use the Integer 7.  We have made, then, a global declaration and have
initialized the variable to the value 7. The word "global" refers to the
fact that wherever we use the name now, it will always refer to the
variable we have created; the word "initialized" indicates that, upon
creation, it was first assigned a particular value, in this case the
Integer 7.

Let's consider a few examples.

a = 20.71

b = a^2+a-1

Notice here that the value of "b" is not saved as "a^2+a-1", but as a Real
value of around 448.614.   Remember, the right-hand side is evaluated
first, and then the new value is assigned to the variable.

If we change the value of "a", the variable "b" will not change, as follows:

a = 19

b

We can ask Mathematica what it knows about a variable, or, for that matter,
any "name".  Let's ask what it knows about "b":

?b

What Mathematica is telling us is that "b" is globally declared, and its
latest value is 448.6141.

Functional Forms

In Mathematica, there are usually several ways to accomplish any operation.
For the value assignment operation we have performed above, we have an
alternative functional form, Set[ ]. (Functional form refers to using a
name with brackets to complete an operation, rather than using a special
symbol, like the equals sign.)  Sometimes functions have expressions placed
in between the brackets, and we call them arguments, or parameters.  If the
number of arguments is greater than 1, then the arguments are separated by
commas (as in "N[Pi,50]").  For our function Set[ ], the first argument is
the name we want to declare and initialize.  The second argument is the
value to which we want to initialize the name.  In short, then, "mess = 7"
can be accomplished in functional form by evaluating "Set[mess,7]".
Remember that just as with the assignment operation using the equals sign,
this second argument will be evaluated first before the assignment happens.

Set[a,20.71]

Finally, we consider one more example.

bigmess = Expand[(x+2)^10]

bigmess

All of the operators which we have seen have special functional forms.
Here is a list of the operators, together with their functional forms:

a>b      Greater[a,b]
a>=b    GreaterEqual[a,b]
a<b      Less[a,b]
a<=b    LessEqual[a,b]
a==b    Equal[a,b]
a!=b     NotEqual[a,b]
!a         Not[a]
a&&b  And[a,b]
a||b       Or[a,b]

Variable (Re)Assignment after Initialization

Once a variable, or any name, is declared and initialized, it may be
redefined or reassigned.  Once we do so, Mathematica essentially forgets
the first value, and from that point forward until another redefinition,
the name will refer to the new value.

mess = 9

If we execute the statement above, then "mess" will then refer to the value
9, of Integer type.  Although this is the desired behavior, here is a
caveat:  if we return to an earlier cell in our notebook and reevaluate
each cell, we may get different answers than we did before.  For instance,
if earlier cells included the instructions "mess=8" and "bigmess =
mess^10", the first time we evaluate them we would find that bigmess is
8^10.  However, if we execute "mess = 9" and go back  to and reevaluate the
second of the first two cells ("bigmess = mess^10"), then we will find that
bigmess has changed to 9^10.

Modifying a Variable's Value with Arithmetic Operations

Frequently we will want to take a variable's value, do something simple to
it, such as add 3 to it or multiply it by 4, and put the new value back
into the variable.  We are, then, reassigning the value, based on the old
value.  We can accomplish these operations using the equals sign just as
before, remembering that the right-hand side is evaluated before  the
assignment is made.  Consider the following cell:

mess = 10;
mess = mess + 10

(Note that the semicolon suppresses the output of the line on which it
occurs and separates the two lines.)  What happens in the second line is
that "mess + 10" is evaluated to the Integer 20, and then this is
reassigned to "mess".  For the mathematically inclined, the statement
"x=x+10" will seem an inconsistency, but for (we) computer programmers it
is crucial to remember that the equals sign invokes an action (assignment)
and does not claim an equality.  (Recall that the double equals sign "=="
is the equality test.)

Here are some more examples of arithmetic value modification:

mess = mess * 10

mess = mess / 20

mess = 2 + 10 / 5 + mess / 2

There are other assignment operators which we will use from time to time,
and these operators are essentially shorthand for longer expressions.
They are used when we want to take and old value of a variable, perform one
arithmetic operation to it, and replace the value.  The operator "+=" adds
the (evaluated) right-hand side to the variable on the left and reassigns
it.  As an example:

mess = 8;
mess += 1

Other examples:

mess -= 1

mess *= (2+10)

mess /= 4

Of course, if we wish to assign a value to a variable based on other
variables, then these shorthand operations will not help.  For instance,
there is no shorthand for the following expression.

mess2 = mess * 2

For completeness' sake, here are the functional forms of these operators:

a+=b       AddTo[a,b]
a-=b        SubtractFrom[a,b]
a*=b       MultiplyBy[a,b]
a/=b        DivideBy[a,b]

Increment, Decrement, PreIncrement, PreDecrement

One very common way in which computer programmers change values of
variables is to add 1 or subtract 1 from a variable; this is useful in
loops, where we do a certain operation (say) 10 times.  In that instance we
will need to initialize a variable to 1, add 1 each time we do the
operation, and continue doing so until the variable reaches 10.  Adding one
to a variable is called incrementing the variable, while subtracting one is
called decrementing  the variable. There are some useful shorthand
expressions for incrementing and decrementing, namely "++" and "--". You
can use either one by placing it either immediately before or immediately
after the name of the variable, as for instance "i++", "i--", "++i", and
"--i".  As you might expect, "++" adds one (the Integer 1) to the variable,
while "--" takes 1 away.

There is one subtle difference between placing a "++" or "--" expression
before and placing it after the name:  when  the incrementing or
decrementing happens.  If you put the "++" or "--" before  the variable,
then the incrementing or decrementing happens before  the value is used in
the current expression; if you place it after, then the incrementing or
decrementing happens afterwards.

Let's look at some examples. Suppose "mess" starts out as 8:

mess = 8

Now let's add one to it and find the new value:

++mess

What happened is that we asked for the value of mess, but the "++" had to
happen before the value was used in the evaluation of the line, so "mess"
was incremented to 9 and then returned to us.  Now let's ask for the value
of mess with a increment afterwards:

mess++

We still get 9, but "mess" is really now 10!  To convince ourselves of
this, let's find out what mess is:

mess

What happened?  When we executed "mess++", the expression's value was that
of "mess", which was 9, and after  the evaluation happened (and we were
returned the value 9), mess was incremented. Then we asked for the value of
"mess", and the expression "mess" evaluated to its new value, namely, 10.

Functional forms for the increment and decrement operators are as follows:

a++       Increment[a]
a--         Decrement[a]
++a       PreIncrement[a]
--a         PreIncrement[a]

We can always find the functional form for an expression by using the
function "FullForm[ ]".  For instance, "FullForm[a<b]" will return
"Less[a,b]".

Deassignment, Undeclaration

What if we want to get rid of a variable's value?  For instance, what if we
want to have a polynomial "f" be the expression "x^2+x+1" and "x" has
already been declared and initialized to the Integer 5?  Then if we set "f"
to be "x^2+x+1" then we will get 31, not "x^2+x+1"!  One solution is to
tell Mathematica to forget about the value of "x".  There are several ways
to accomplish this, one of which is to use the function "Clear[ ]".  The fun
ction "Clear[ ]" erases the value of each name appearing as an argument to
it.  For example:

mess = 9

Clear[mess]

mess

(A shorthand for Clear[mess] is "mess =."  Yes, include the period right
after the equals.  Actually, "=." is a shorthand for the function "Unset[
]", which is somewhat different from "Clear[ ]", but we will ignore the
differences for now. The most powerful of Mathematica's undeclaration
functions is "Remove[ ]".  When "Clear[ ]" erases a value, Mathematica
still remembers that the name has been used somewhere (so that it is still
declared); "Remove[ ]" instructs Mathematica to forget that it ever saw the
name.)

Function Definition: SetDelayed

Let's think again about how we defined "b" above.  What if, instead of
computing the value of a^2+a-1 with the value of "a" which is currently
defined, we wish to have Mathematica compute the value of the function
x^2+x-1 for any given value of x?  The best way to do this in Mathematica
is to define a function.  A function typically has several arguments or
parameters, and the function operates by taking the values it is given for
those arguments and using them in some expression or sequence of
operations.  When we define a function, we must give Mathematica a name for
each of these parameters, but we must distinguish these names from the
global names which we might already have declared.  Here's how to do it:
First, on the left-hand side of the function definition, when names for
each argument are given between the brackets (separated by commas, as
usual), attach an underscore ("_") immediately following each one. Second,
instead of using "0"=, use colon-equals (":=", the delayed assignment
operator ). For example:

Clear[f]
f[x_] := x^2 + x - 1

This line tells Mathematica several things.  First, it must declare a new
name, "f"; second, this instance of "f" may take exactly one argument or
parameter; third, if "f" is evaluated with an expression in between the
brackets, that expression will (temporarily) be called "x"; finally, the
function "f" will take this new "x" and use it in the expression on the
right-hand side to provide an answer.  An important fact to remember is
that, unlike the scenario with the assignment operator "=", the right-hand
side is not evaluated at all.  Let's use "f":

f[2]

There are some terms appropriate here.  A formal parameter is a name
assigned inside a function declaration to be used for one of the arguments
of the function.  Formal parameters in Mathematica are distinct from global
names.  In the case above, "x" is a formal parameter.  An actual parameter,
on the other hand, is a value with which the function is actually
evaluated.  In the case above, the "2" in "f[2]" was an actual parameter.
Actual parameters need not be Integers, of course; we can call "f" with
anything we like inside the brackets:

f[y]    (* y is called an actual parameter *)

f[a]    (* a is called an actual parameter *)

f[7]    (* 7 is called an actual parameter *)

Even more, we can use "x" as an actual parameter, and Mathematica will
realize that it is distinct from the formal parameter "x"!

f[x]    (* here, the x is an actual parameter *)

As you may have noticed, using "(*" and "*)" around some text in an input
cell allows you to compose a comment that Mathematica will ignore.  When
our code gets especially complicated, we will comment more often.

The functional form of the colon-equals operator is SetDelayed[ ].  The
following two input cells are then equivalent:

Clear[myFunction]
myFunction[x_] := Sin[x] + Cos[x]

SetDelayed [myFunction[x_], Sin[x] + Cos[x] ]

In order to reinforce the need for underscores and the colon-equals sign
symbol, let's look at what can happen when you don't do one or the other of
our requirements.

Leaving Out the Underscore

If we leave out the underscore, Mathematica no longer sees the argument as
a formal parameter into which any expression can be substituted.  Instead,
it simply remembers the name of the function and decides that if the
parameter is ever exactly  the one we specify, the function will return
whatever right-hand side we wrote down.  For instance:

Clear[bad]

bad[x] := x^2 + x - 1

bad[x]

bad[y]

bad[7]

This is clearly not the behavior we want in a general function.

Using = Instead of := (Set Instead of SetDelayed)

If we use equals instead of colon-equals, Mathematica will immediately
evaluate the right-hand side of the equals sign and then assign the
resulting expression to our function.  While this sometimes produces the
desired outcome, it can be a dangerous operation.  Consider the following
sequence of steps:

x = 2
h[x_] = x^2+x+1

Mathematica has declared a function "h" which takes one formal parameter
"x", but the expression the function will evaluate with "x" is not
"x^2+x+1" but the Integer 7!  This example explains the meaning of the
functional name "SetDelayed":  Mathematica delays   evaluating the
right-hand side until after the function is used; it does not evaluate the
right-hand side when the function is defined.  Let's convince ourselves
that "h" has an undesirable definition:

h[1]

h[2]

h[y]

?h

It is certainly true that in our example above, evaluating the command
"Remove[x]" before defining the function using the equals sign would have
made "h" a well-defined function. However, there are situations in which
deciding whether the equals sign will work can be quite delicate, and we
hope that the first impulse will be to use colon-equals.

The Naming of Functions

One good programming principle is name the functions we create differently
from functions which are basic to the programming language itself.  For
instance, we probably shouldn't try to define our own function called
"Plot[ ]".  Thankfully, Mathematica prevents us from doing so (by giving
all of its own functions the "Protected" attribute, as we will see later).
Still, we should distinguish our own functions from those of Mathematica by
using a different convention in function naming:  we shouldn't capitalize
the first letter of our function name.  We are free, however, to capitalize
the first letters of successive words in the function name, in order to
make their names more readable.  Some examples of good names for
user-defined functions are "myFunction", "plotMyFunction",
"takeMyDerivative", "initializeMyVariables".

One caveat is that, in Mathematica, functions can have the same names as
variables, and if this happens, confusion erupts.  For instance, if we
define "f[x_] := x^2" and then evaluate "f = x + 2", Mathematica will try
to remember both.  Let's try it:

Clear[func,x]
func[x_] := x^2
func = x + 2

?func

Hence, to refer to the function defined above, it will be necessary to use
brackets and put some expression between the brackets.  To plot the
function "func", then, we must specify "func[x]", not "func", but if "func"
is already defined separately as a variable, then Mathematica will make a
mistake and try unsuccessfully to evaluate the expression "x+2[x]".  Notice
that in the plot below we get a plot of "x+2", not "x^2":

Plot[func,{x,-1,1}]

The solution is never to have two expressions with the same name, and
always to refer to a function using brackets.

Using Set for Function Definition (Beware.)

You may wish to skip this section for a while, maybe even for a week or
two.  If you're unsure, just go ahead an close the cell group!  The purpose
of this section is to show you that you may in fact want to use the
assignment operator "=" to define a function.  We'll give two examples, one
where to do so would make the situation easier, another where it would be a
mistake.

Example 1: Where = is good

First, we introduce the derivative function "D[ ]", which differentiates
the first argument with respect to the variable stated in the second
argument.  (For the purposes of this example, we need only know that the
derivative function applied to a polynomial returns another polynomial.)
Let's try to define a function finds the derivative of a certain polynomial
(let's say x^2+x-1, for simplicity) and then substitutes a particular value
for x inside the new polynomial. The parameter of our function, then, will
be this particular value.  We might write

Clear[g]
g[x_] := D[-1+x+x^2, x]

But this would be a terrible mistake.  Why?  Because when we ask for, say,
"g[3]" the value 3  would be substituted into the entire right-hand side
everywhere there is an "x", and so Mathematica will try to evaluate
"D[11,3]", which, first, doesn't make sense (since the second argument is
not a variable) and, second, gives us an error.  What we want is to find
the derivative (with respect to "x") first, and then evaluate at the value
of "x".  We might try the following:

Clear[g]
deriv = D[-1+x+x^2, x];
g[x_] := deriv

Here we simply find the derivative, assign it to the name "deriv", and have
"g" defined to use "deriv" as its right-hand side.  But this doesn't work
either, since "g" is not defined as "1+2x"
(the derivative of "-1+x+x^2"), but simply as "deriv".  We ask, why wasn't
"1+2x" substituted for "deriv" in the second line?  Because SetDelayed (or
":=") doesn't evaluate the right-hand side before it defines the function.
To check,

?g

Now we are upset.  We can force Mathematica to evaluate "deriv" before it
defines the function.  We can do so as follows:

Clear[g]
deriv = D[-1+x+x^2,x];
g[x_] := Evaluate[deriv]

To do this, however, is basically to walk a long way around the simpler
expression, using "=", which does basically the same thing:

Clear[g]
g[x_] = D[-1+x+x^2,x]

Example 2:  Where = is bad

In this example, we use the "Random[ ]" function, which finds a random
value of the type specified by the first argument, in an interval specified
as "{begin, end}" in the second argument.  (For instance,
"Random[Real,{0,1}]" produces a random approximate number between 0 and 1.
See "?Random" for more information.)  We wish to define a function taking
one argument (say "n") which returns a random integer from 1 to the number
we specify ("n").  If we try defining the function with the assignment
operator "=" we certainly have a problem, since Mathematica tries to
evaluate the right-hand side before assigning the definition to the name of
our function, and at that point Mathematica doesn't know a value for "n":

Clear[rand,n];
rand[n_] = Random[Integer,{1,n}]

But if we use the delayed assignment operator ":=", all works out right.

Clear[rand];
rand[n_] := Random[Integer,{1,n}]

rand[100]

rand[50]