proc -- define a procedure
Introductionproc - end_proc defines a procedure.
Call(s)
(x1, x2, ...) -> body
proc(
x1 <= default1> <: type1>,
x2 <= default2> <: type2>, ...
) <: returntype>
<name pname;>
<option option1, option2, ...;>
<local local1, local2, ...;>
<save global1, global2, ...;>
begin
body
end_proc _procdef(...)
Parametersx1, x2, ... |
- | the formal parameters of the procedure: identifiers |
default1, default2, ... |
- | default values for the parameters: arbitrary MuPAD objects |
type1, type2, ... |
- | admissible types for the parameters: type objects as
accepted by the function testtype |
returntype |
- | admissible type for the return value: a type object as
accepted by the function testtype |
pname |
- | the name of the procedure: an expression |
option1, option2, ... |
- | available options are: escape, hold, noDebug, remember |
local1, local2, ... |
- | the local variables: identifiers |
global1, global2, ... |
- | global variables: identifiers |
body |
- | the body of the procedure: an arbitrary sequence of statements |
Returnsa procedure of type DOM_PROC.
Related
Functionsargs, context, debug, expose, hold, MAXDEPTH, newDomain, Pref::ignoreNoDebug, Pref::noProcRemTab, Pref::typeCheck, Pref::warnDeadProcEnv,
return, testargs, Type
Detailsf := proc(x1, x2, ...) ... end_proc may be
called like a system function in the form f(x1, x2, ...).
The return value of this call is the value of the last command executed
in the procedure body (or the value returned by the body via the
function return).(x1, x2, ...) -> body is
equivalent to proc(x1, x2, ...) begin body end_proc. It is
useful for defining simple procedures that do not need local
variables. E.g., f := x -> x^2 defines the mathematical
function f: x -> x^2. If the procedure uses more than one
parameter, use brackets as in f := (x, y) -> x^2 + y^2.
Cf. example 1.f := proc(x = 42) begin body end_proc
defines the default value of the parameter x to be
42. The call f() is equivalent to
f(42). Cf. example 2.
f := proc(x : DOM_INT) begin body end_proc
restricts the argument x to integer values. If the
procedure is called with an argument of a wrong data type, the
evaluation is aborted with an error message. Cf. example 3. Checking the input parameters should be a standard
feature of every procedure. Also refer to testargs.
Also an automatic type checking for the return value may be
implemented specifying returntype. Cf. example 3.
name, a name may be defined for the
procedure, e.g.,
f := proc(...) name myName; begin body end_proc.
There is a special variable procname associated with a
procedure which stores its name. When the body returns a symbolic call
procname(args()), the actual name is substituted. This is
the name defined by the optional name entry. If no
name entry is specified, the first identifier the
procedure has been assigned to is used as the name, i.e.,
f in this case. Cf. example 4.
option, special features may be
specified for a procedure:Pref::warnDeadProcEnv.Pref::ignoreNoDebug. Cf.
example 7.Pref::noProcRemTab. local, the local variables of the
procedure are specified, e.g.,
f := proc(...) local x, y; begin body end_proc.
Cf. example 9.
Local variables cannot be used as ``symbolic variables'' (identifiers). They must be assigned values before they can be used in computations.
Note that the names of global MuPAD variables such DIGITS, READPATH etc. should not be used as
local variables. Also refer to the keyword save.
save, a local context for global
MuPAD variables is created, e.g.,
f := proc(...) save DIGITS; begin DIGITS := newValue; ...
end_proc.
This means that the values these variables have on entering the procedure are restored on exiting the procedure. This is true even if the procedure is exited because of an error. Cf. example 10.
args. Cf. example 11.f, say, usually does not
print the source code of the body to the screen. Use expose(f) to see the body. Cf.
example 12.MAXDEPTH limits the ``nesting
depth'' of recursive procedure calls. The default value is
MAXDEPTH = 500. Cf. example 8.dom contains the
name of the domain the slot belongs to. If the procedure is not a
domain slot, the value of dom is NIL.end_proc, also the keyword end
can be used.proc - end_proc internally
results in a call of the kernel function _procdef. There
is no need to call _procdef directly._procdef is a function of the system kernel.
Example
1Simple procedures can be generated with the ``arrow
operator'' ->:
>> f := x -> x^2 + 2*x + 1: f(x), f(y), f(a + b), f(1.5)
2 2 2
2 x + x + 1, 2 y + y + 1, 2 a + 2 b + (a + b) + 1, 6.25
>> f := n -> isprime(n) and isprime(n + 2): f(i) $ i = 11..18
TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE
The following command maps an ``anonymous'' procedure to the elements of a list:
>> map([1, 2, 3, 4, 5, 6], x -> x^2)
[1, 4, 9, 16, 25, 36]
>> delete f:
Example
2The declaration of default values is demonstrated. The following procedure uses the default values if the procedure call does not provide all parameter values:
>> f := proc(x, y = 1, z = 2) begin [x, y, z] end_proc: f(x, y, z), f(x, y), f(x)
[x, y, z], [x, y, 2], [x, 1, 2]
No default value was declared for the first argument. A warning is issued if this argument is missing:
>> f()
Warning: Uninitialized variable 'x' used;
during evaluation of 'f'
[NIL, 1, 2]
>> delete f:
Example
3The automatic type checking of procedure arguments and return values is demonstrated. The following procedure accepts only positive integers as argument:
>> f := proc(n : Type::PosInt) begin n! end_proc:
An error is raised if an unsuitable parameter is passed:
>> f(-1)
Error: Wrong type of 1. argument (type 'Type::PosInt' expected,
got argument '-1');
during evaluation of 'f'
In the following procedure, automatic type checking of the return value is invoked:
>> f := proc(n : Type::PosInt) : Type::Integer
begin
n/2
end_proc:
An error is raised if the return value is not an integer:
>> f(3)
Error: Wrong type of return value (type 'Type::Integer' expected,
value is '3/2');
during evaluation of 'f'
>> delete f:
Example
4The name entry of procedures is
demonstrated. A procedure returns a symbolic call to itself by using
the variable procname that contains the current procedure
name:
>> f := proc(x)
begin
if testtype(x,Type::Numeric)
then return(float(1/x))
else return(procname(args()))
end_if
end_proc:
f(x), f(x + 1), f(3), f(2*I)
f(x), f(x + 1), 0.3333333333, - 0.5 I
Also error messages use this name:
>> f(0)
Error: Division by zero;
during evaluation of 'f'
If the procedure has a name entry, this entry is used:
>> f := proc(x)
name myName;
begin
if testtype(x,Type::Numeric)
then return(float(1/x))
else return(procname(args()))
end_if
end_proc:
f(x), f(x + 1), f(3), f(2*I)
myName(x), myName(x + 1), 0.3333333333, - 0.5 I
>> f(0)
Error: Division by zero;
during evaluation of 'myName'
>> delete f:
Example
5The option escape is demonstrated. This option must be used if the procedure returns another procedure that references a formal parameter or a local variable of the generating procedure:
>> f := proc(n)
begin
proc(x) begin x^n end_proc
end_proc:
Without the option escape, the
formal parameter n of f leaves its scope:
g := f(3) references n internally. When
g is called, it cannot evaluate n to the
value 3 that n had inside the scope of the
function f:
>> g := f(3): g(x)
Warning: Uninitialized variable 'unknown' used;
during evaluation of 'g'
Error: Illegal operand [_power];
during evaluation of 'g'
option escape
instructs the procedure f to deal with variables escaping
the local scope. Now, the procedure g := f(3) references
the value 3 rather than the formal parameter
n of f, and g can be executed
correctly:
>> f := proc(n)
option escape;
begin
proc(x) begin x^n end_proc
end_proc:
g := f(3): g(x), g(y), g(10)
3 3
x , y , 1000
>> delete f, g:
Example
6The option hold is demonstrated.
With hold, the procedure
sees the actual parameter in the form that was used in the procedure
call. Without hold, the
function only sees the value of the parameter:
>> f := proc(x) option hold; begin x end_proc: g := proc(x) begin x end_proc: x := PI/2: f(sin(x) + 2) = g(sin(x) + 2), f(1/2 + 1/3) = g(1/2 + 1/3)
sin(x) + 2 = 3, 1/2 + 1/3 = 5/6
Procedures using option hold can evaluate the arguments with the function context:
>> f := proc(x) option hold; begin x = context(x) end_proc: f(sin(x) + 2), f(1/2 + 1/3)
sin(x) + 2 = 3, 1/2 + 1/3 = 5/6
>> delete f, g, x:
Example
7The option noDebug is
demonstrated. The debug
command starts the debugger which steps inside the procedure
f. After entering the debugger command c
(continue), the debugger continues the evaluation:
>> f := proc(x) begin x end_proc: debug(f(42))
Activating debugger...
#0 in f($1=42) at /tmp/debug0.556:4
mdx> c
Execution completed.
42
With the option noDebug, the debugger does not step into the procedure:
>> f := proc(x) option noDebug; begin x end_proc: debug(f(42))
Execution completed.
42
>> delete f:
Example
8The option remember is
demonstrated. The print
command inside the following procedure indicates if the procedure body
is executed:
>> f:= proc(n : Type::PosInt)
option remember;
begin
print("computing ".expr2text(n)."!");
n!
end_proc:
f(5), f(10)
"computing 5!"
"computing 10!"
120, 3628800
When calling the procedure again, all values that were computed before are taken from the internal ``remember table'' without executing the procedure body again:
>> f(5)*f(10) + f(15)
"computing 15!"
1308109824000
option remember is
used in the following procedure which computes the Fibonacci numbers F(0) = 0, F(1) =
1, F(n) = F(n - 1) + F(n - 2) recursively:
>> f := proc(n : Type::NonNegInt)
option remember;
begin
if n = 0 or n = 1 then return(n) end_if;
f(n - 1) + f(n - 2)
end_proc:
>> f(123)
22698374052006863956975682
Due to the recursive nature of f, the
arguments are restricted by the maximal recursive depth (see MAXDEPTH):
>> f(1000)
Error: Recursive definition [See ?MAXDEPTH];
during evaluation of 'Type::testtype'
Without option remember, the recursion is rather slow:
>> f := proc(n : Type::NonNegInt)
begin
if n = 0 or n = 1 then return(n) end_if;
f(n - 1) + f(n - 2)
end_proc:
>> f(28)
317811
>> delete f:
Example
9We demonstrate the use of local variables:
>> f := proc(a)
local x, y;
begin
x := a^2;
y := a^3;
print("x, y" = (x, y));
x + y
end_proc:
The local variables x and y do
not coincide with the global variables x, y
outside the procedure. The call to f does not change the
global values:
>> x := 0: y := 0: f(123), x, y
"x, y" = (15129, 1860867)
1875996, 0, 0
>> delete f, x, y:
Example
10The save declaration is demonstrated. The
following procedure changes the environment variable DIGITS internally. Because of
save DIGITS, the original value of DIGITS is restored after return from
the procedure:
>> myfloat := proc(x, digits)
save DIGITS;
begin
DIGITS := digits;
float(x);
end_proc:
The current value of DIGITS is:
>> DIGITS
10
With the default setting DIGITS = 10, the following
float conversion suffers from numerical cancellation. Due to the higher
internal precision, myfloat produces a more accurate
result:
>> x := 10^20*(PI - 21053343141/6701487259): float(x), myfloat(x, 20)
-32.0, 0.02616403997
The value of DIGITS was not changed by the call to
myfloat:
>> DIGITS
10
The following procedure needs a global identifier,
because local variables cannot be used as integration variables in the
int function. Internally,
the global identifier x is deleted to make sure that
x does not have a value:
>> f := proc(n)
save x;
begin
delete x;
int(x^n*exp(-x), x = 0..1)
end_proc:
>> x := 3: f(1), f(2), f(3)
1 - 2 exp(-1), 2 - 5 exp(-1), 6 - 16 exp(-1)
Because of save x, the previously assigned
value of x is restored after the integration:
>> x
3
>> delete myfloat, x, f:
Example
11The following procedure accepts an arbitrary number of
arguments. It accesses the actual parameters via args, puts them into a list, reverses
the list via revert,
and returns its arguments in reverse order:
>> f := proc()
local arguments;
begin
arguments := [args()];
op(revert(arguments))
end_proc:
>> f(a, b, c)
c, b, a
>> f(1, 2, 3, 4, 5, 6, 7)
7, 6, 5, 4, 3, 2, 1
>> delete f:
Example
12Use expose to see the source code of a
procedure:
>> f := proc(x = 0, n : DOM_INT)
begin
sourceCode;
end_proc
proc f(x, n) ... end
>> expose(f)
proc(x = 0, n : DOM_INT)
name f;
begin
sourceCode
end_proc
>> delete f:
DOM_EXEC, generated by
fun and func in previous versions, do not
exist any longer.DIGITS could be declared as
local variables if the procedure changed them locally. In the present
version, this does not work any longer. Instead, the new keyword
save was introduced.end can be used in
addition to end_proc to close a procedure definition.