proc
-- define a procedureproc - end_proc
defines a procedure.
(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(...)
x1, 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 |
a procedure of type DOM_PROC
.
args
, context
, debug
, expose
, hold
, MAXDEPTH
, newDomain
, Pref::ignoreNoDebug
, Pref::noProcRemTab
, Pref::typeCheck
, Pref::warnDeadProcEnv
,
return
, testargs
, Type
f := 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.Simple 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:
The 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:
The 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:
The 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:
The 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:
The 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:
The 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:
The 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:
We 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:
The 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:
The 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:
Use 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.