123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- \chapter{Procedures}\ttindex{PROCEDURE}
- It is often useful to name a statement for repeated use in calculations
- with varying parameters, or to define a complete evaluation procedure for
- an operator. {\REDUCE} offers a procedural declaration for this purpose. Its
- general syntax is:
- \begin{verbatim}
- [<procedural type>] PROCEDURE <name>[<varlist>];<statement>;
- \end{verbatim}
- where
- \begin{verbatim}
- <varlist> ::= (<variable>,...,<variable>)
- \end{verbatim}
- This will be explained more fully in the following sections.
- In the algebraic mode of {\REDUCE} the {\tt <procedure type>} can be
- omitted, since the default is {\tt ALGEBRAIC}. Procedures of type {\tt
- INTEGER} or {\tt REAL} may also be used. In the former case, the system
- checks that the value of the procedure is an integer. At present, such
- checking is not done for a real procedure, although this will change in
- the future when a more complete type checking mechanism is installed.
- Users should therefore only use these types when appropriate. An empty
- variable list may also be omitted.
- All user-defined procedures are automatically declared to be operators.
- In order to allow users relatively easy access to the whole {\REDUCE} source
- program, system procedures are not protected against user redefinition. If
- a procedure is redefined, a message
- \begin{verbatim}
- *** <procedure name> REDEFINED
- \end{verbatim}
- is printed. If this occurs, and the user is not redefining his own
- procedure, he is well advised to rename it, and possibly start over
- (because he has {\em already\/} redefined some internal procedure whose correct
- functioning may be required for his job!)
- All required procedures should be defined at the top level, since they
- have global scope throughout a program. In particular, an attempt to
- define a procedure within a procedure will cause an error to occur.
- \section{Procedure Heading}\index{Procedure heading}
- Each procedure has a heading consisting of the word {\tt PROCEDURE}
- (optionally preceded by the word {\tt ALGEBRAIC}), followed by the name of
- the procedure to be defined, and followed by its formal parameters -- the
- symbols that will be used in the body of the definition to illustrate
- what is to be done. There are three cases:
- \begin{enumerate}
- \item No parameters. Simply follow the procedure name with a terminator
- (semicolon or dollar sign).
- \begin{verbatim}
- procedure abc;
- \end{verbatim}
- When such a procedure is used in an expression or command, {\tt abc()}, with
- empty parentheses, must be written.
- \item One parameter. Enclose it in parentheses {\em or\/} just leave at
- least one space, then follow with a terminator.
- \begin{verbatim}
- procedure abc(x);
- \end{verbatim}
- or
- \begin{verbatim}
- procedure abc x;
- \end{verbatim}
- \item More than one parameter. Enclose them in parentheses, separated by
- commas, then follow with a terminator.
- \begin{verbatim}
- procedure abc(x,y,z);
- \end{verbatim}
- \end{enumerate}
- Referring to the last example, if later in some expression being evaluated
- the symbols {\tt abc(u,p*q,123)} appear, the operations of the procedure
- body will be carried out as if {\tt X} had the same value as {\tt U} does,
- {\tt Y} the same value as {\tt p*q} does, and {\tt Z} the value 123. The
- values of {\tt X}, {\tt Y}, {\tt Z}, after the procedure body operations
- are completed are unchanged. So, normally, are the values of {\tt U},
- {\tt P}, {\tt Q}, and (of course) 123. (This is technically referred to as
- call by value.)\index{Call by value}
- The reader will have noted the word {\em normally\/} a few lines earlier. The
- call by value protections can be bypassed if necessary, as described
- elsewhere.
- \section{Procedure Body}\index{Procedure body}
- Following the delimiter that ends the procedure heading must be a {\em
- single} statement defining the action to be performed or the value to be
- delivered. A terminator must follow the statement. If it is a semicolon,
- the name of the procedure just defined is printed. It is not printed if a
- dollar sign is used.
- If the result wanted is given by a formula of some kind, the body is just
- that formula, using the variables in the procedure heading.
- {\it Simple Example:}
- If {\tt f(x)} is to mean {\tt (x+5)*(x+6)/(x+7)}, the entire procedure
- definition could read
- \begin{verbatim}
- procedure f x; (x+5)*(x+6)/(x+7);
- \end{verbatim}
- Then {\tt f(10)} would evaluate to 240/17, {\tt f(a-6)} to
- {\tt A*(A-1)/(A+1)}, and so on.
- {\it More Complicated Example:}
- Suppose we need a function {\tt p(n,x)} that, for any positive integer
- {\tt N}, is the Legendre polynomial\index{Legendre polynomials} of order
- {\em n}. We can define this operator using the
- textbook formula defining these functions:
- \begin{displaymath}
- p_n(x) = \displaystyle{1\over{n!}}\
- \displaystyle{d^n\over dy^n}\ \displaystyle{{1\over{(y^2 - 2xy + 1)
- ^{{1\over2}}}}}\Bigg\vert_{y=0}
- \end{displaymath}
- Put into words, the Legendre polynomial $p_n(x)$ is the result of
- substituting $y=0$ in the $n^{th}$ partial derivative with respect to $y$
- of a certain fraction involving $x$ and $y$, then dividing that by $n!$.
- This verbal formula can easily be written in {\REDUCE}:
- \begin{verbatim}
- procedure p(n,x);
- sub(y=0,df(1/(y^2-2*x*y+1)^(1/2),y,n))
- /(for i:=1:n product i);
- \end{verbatim}
- Having input this definition, the expression evaluation
- \begin{verbatim}
- 2p(2,w);
- \end{verbatim}
- would result in the output
- \begin{verbatim}
- 2
- 3*W - 1 .
- \end{verbatim}
- If the desired process is best described as a series of steps, then a group
- or compound statement can be used.
- \extendedmanual{\newpage}
- {\it Example:}
- The above Legendre polynomial example can be rewritten as a series of steps
- instead of a single formula as follows:
- \begin{verbatim}
- procedure p(n,x);
- begin scalar seed,deriv,top,fact;
- seed:=1/(y^2 - 2*x*y +1)^(1/2);
- deriv:=df(seed,y,n);
- top:=sub(y=0,deriv);
- fact:=for i:=1:n product i;
- return top/fact
- end;
- \end{verbatim}
- Procedures may also be defined recursively. In other words, the procedure
- body\index{Procedure body} can include references to the procedure name
- itself, or to other procedures that themselves reference the given
- procedure. As an example, we can define the Legendre polynomial through
- its standard recurrence relation:
- \begin{verbatim}
- procedure p(n,x);
- if n<0 then rederr "Invalid argument to P(N,X)"
- else if n=0 then 1
- else if n=1 then x
- else ((2*n-1)*x*p(n-1,x)-(n-1)*p(n-2,x))/n;
- \end{verbatim}
- The operator {\tt REDERR}\ttindex{REDERR} in the above example provides
- for a simple error exit from an algebraic procedure (and also a block).
- It can take a string as argument.
- It should be noted however that all the above definitions of {\tt p(n,x)} are
- quite inefficient if extensive use is to be made of such polynomials, since
- each call effectively recomputes all lower order polynomials. It would be
- better to store these expressions in an array, and then use say the
- recurrence relation to compute only those polynomials that have not already
- been derived. We leave it as an exercise for the reader to write such a
- definition.
- \section{Using LET Inside Procedures}
- By using {\tt LET}\ttindex{LET} instead of an assignment in the procedure
- body\index{Procedure body} it is possible to bypass the call-by-value
- \index{Call by value} protection. If {\tt X} is a formal parameter or local
- variable of the procedure (i.e. is in the heading or in a local
- declaration), and {\tt LET} is used instead of {\tt :=} to make an
- assignment to {\tt X}, e.g.
- \begin{verbatim}
- let x = 123;
- \end{verbatim}
- then it is the variable that is the value of {\tt X} that is changed.
- This effect also occurs with local variables defined in a block. If the
- value of {\tt X} is not a variable, but a more general expression, then it
- is that expression that is used on the left-hand side of the {\tt LET}
- statement. For example, if {\tt X} had the value {\tt p*q}, it is as if
- {\tt let p*q = 123} had been executed.
- \section{LET Rules as Procedures}
- The {\tt LET}\ttindex{LET} statement offers an alternative syntax and
- semantics for procedure definition.
- In place of
- \begin{verbatim}
- procedure abc(x,y,z); <procedure body>;
- \end{verbatim}
- one can write
- \begin{verbatim}
- for all x,y,z let abc(x,y,z) = <procedure body>;
- \end{verbatim}
- There are several differences to note.
- If the procedure body contains an assignment to one of the formal
- parameters, e.g.
- \begin{verbatim}
- x := 123;
- \end{verbatim}
- in the {\tt PROCEDURE} case it is a variable holding a copy of the first
- actual argument that is changed. The actual argument is not changed.
- In the {\tt LET} case, the actual argument is changed. Thus, if {\tt ABC}
- is defined using {\tt LET}, and {\tt abc(u,v,w)} is evaluated, the value
- of {\tt U} changes to 123. That is, the {\tt LET} form of definition
- allows the user to bypass the protections that are enforced by the call
- by value conventions of standard {\tt PROCEDURE} definitions.
- {\it Example:} We take our earlier {\tt FACTORIAL}\ttindex{FACTORIAL}
- procedure and write it as a {\tt LET} statement.
- \begin{verbatim}
- for all n let factorial n =
- begin scalar m,s;
- m:=1; s:=n;
- l1: if s=0 then return m;
- m:=m*s;
- s:=s-1;
- go to l1
- end;
- \end{verbatim}
- The reader will notice that we introduced a new local variable, {\tt S},
- and set it equal to {\tt N}. The original form of the procedure contained
- the statement {\tt n:=n-1;}. If the user asked for the value of {\tt
- factorial(5)} then {\tt N} would correspond to, not just have the value
- of, 5, and {\REDUCE} would object to trying to execute the statement
- 5 := $5-1$.
- If {\tt PQR} is a procedure with no parameters,
- \begin{verbatim}
- procedure pqr;
- <procedure body>;
- \end{verbatim}
- it can be written as a {\tt LET} statement quite simply:
- \begin{verbatim}
- let pqr = <procedure body>;
- \end{verbatim}
- To call {\em procedure\/} {\tt PQR}, if defined in the latter form, the empty
- parentheses would not be used: use {\tt PQR} not {\tt PQR()} where a call
- on the procedure is needed.
- The two notations for a procedure with no arguments can be combined. {\tt PQR}
- can be defined in the standard {\tt PROCEDURE} form. Then a {\tt LET}
- statement
- \begin{verbatim}
- let pqr = pqr();
- \end{verbatim}
- would allow a user to use {\tt PQR} instead of {\tt PQR()} in calling the
- procedure.
- A feature available with {\tt LET}-defined procedures and not with procedures
- defined in the standard way is the possibility of defining partial
- functions.\index{Function}
- \begin{verbatim}
- for all x such that numberp x let uvw(x)=<procedure body>;
- \end{verbatim}
- Now {\tt UVW} of an integer would be calculated as prescribed by the procedure
- body, while {\tt UVW} of a general argument, such as {\tt Z} or {\tt p+q}
- (assuming these evaluate to themselves) would simply stay {\tt uvw(z)}
- or {\tt uvw(p+q)} as the case may be.
|