|
Say we type the following,
> temp := 7;
> f := function(a,b)
> temp := a * b;
> return temp^2;
> end function;
If the evaluation process is now followed verbatim, the resultant context
will look like [ (temp,7), (f,FUNC(a,b : 7 := a*b; return 7^2;)) ],
which is quite clearly not what was intended!
What is needed in the previous example is some way of declaring that an
identifier, in this case temp, is a `new' identifier (i.e., distinct from
other identifiers with the same name) whose use is confined to the enclosing
function. Magma provides such a mechanism, called a local declaration.
The previous example could be written,
> temp := 7;
> f := function(a,b)
> local temp;
> temp := a * b;
> return temp^2;
> end function;
The identifier temp inside the body of f is said to be `(declared) local'
to the enclosing function. Evaluation of these two assignments would result in
the context being [ (temp, 7), (f, FUNC(a,b : local temp := a*b;
return local temp^2;)) ] as intended.
It is very important to remember that temp and local temp are distinct!
Hence if we now type,
> r := f(3,4);
the resultant context would be [ (temp,7), (f,FUNC(a,b : local temp
:= a*b; return local temp^2;)), (r,144) ]. The assignment to local temp
inside
the body of f does not change the value of temp outside the function.
The effect of an assignment to a local identifier is thus localized to the
enclosing function.
It can become tedious to have to declare all the local variables used in a
function body. Hence Magma adopts a convention whereby an identifier can be
implicitly declared according to how it is first used in a function body. The
convention is that if the first use of an identifier inside a function body is
on the left hand side of a :=, then the identifier is considered to be local,
and the function body is considered to have an implicit local declaration for
this identifier at its beginning. There is in fact no need therefore to declare
temp as local in the previous example as the first use of temp is on the
left hand side of a := and hence temp is implicitly declared local.
It is very important to note that the term `first use' refers to the first
textual use of an identifier. Consider the following example,
> temp := 7;
> f := function(a,b)
> if false then
> temp := a * b;
> return temp;
> else
> temp;
> return 1;
> end if;
> end function;
The first textual use of temp in this function body is in the line
> temp := a * b;
Hence temp is considered as a local inside the function body. It is not
relevant that the if false ... condition will never be true and so the first
time temp will be encountered when f is applied to some arguments is in
the line
> temp;
`First use' means `first textual use', modulo the rule about examining the
right hand side of a := before the left!
It is now necessary to be more precise about the treatment of identifiers in
Magma. Every identifier in a Magma program is considered to belong to one
of three possible classes, these being:
- (a)
- the class of value identifiers
- (b)
- the class of variable identifiers
- (c)
- the class of reference identifiers
The class an identifier belongs to indicates how the identifier is used in a
program.
The class of value identifiers includes all identifiers that stand as
placeholders for values, namely:
- (a)
- all loop identifiers;
- (b)
- the $$ pseudo-identifier;
- (c)
- all identifiers whose first use in a function expression is as a value
(i.e., not on the left hand side of an :=, nor as an actual reference argument to a procedure).
Because value identifiers stand as placeholders for values to be substituted
during the evaluation process, they are effectively constants, and hence they
cannot be assigned to. Assigning to a value identifier would be akin to writing
something like 7 := 8;!
The class of variable identifiers includes all those identifiers which are
declared as local, either implicitly by the first use rule, or explicitly
through a local declaration. Identifiers in this class may be assigned to.
The class of reference identifiers will be discussed later.
The reason it is important to know the class of an identifier is that the
class of an identifier effects how it is treated during the evaluation process.
Previously it was stated that the evaluation process was,
- (1)
- replace each identifier in the expression by its value in the current
context.
- (2)
- simplify the resultant value to its canonical form.
Strictly speaking the first step of this process should read,
- (1')
- replace each free identifier in the expression by its value in the
current context, where an identifier is said to be free if it is a value
identifier which is not a formal argument, a loop identifier, or the $$
identifier.
This definition of the replacement step ensures for example that while
computing the value of a function expression F, Magma does not attempt to
replace F's formal arguments with values from the current context!
As a final point on identifier classes it should be noted that an identifier
may belong to only one class within an expression. Specifically
therefore an identifier can only be used in one way inside a function body.
Consider the following function,
> a := 7;
> f := function(n) a := a; return a; end function;
It is not the case that a is considered as a variable identifier on the
left hand side of the :=, and as a value identifier on the right hand side
of the :=. Rather a is considered to be a value identifier as its first
use is as a value on the right hand side of the := (remember that Magma
inspects the right hand side of an assignment, and hence sees a first as a
value identifier, before it inspects the left hand side where it sees a
being used as a variable identifier).
[Next][Prev] [Right] [Left] [Up] [Index] [Root]
|