Define a procedure
This functionality does not run in MATLAB.
( x_{1}, x_{2}, … ) > body
proc(x_{1}
<=default_{1}
> <:type_{1}
>,x_{2}
<=default_{2}
> <:type_{2}
>, ... ) <: returntype> <name pname;> <optionoption_{1}, option_{2}, …
> <locallocal_{1}, local_{2}, …
> <saveglobal_{1}, global_{2}, …
> begin body end_proc( x_{1}, x_{2}, … ) > body
_procdef(, …
)
proc  end_proc
defines a procedure.
Procedures 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
).
The procedure declaration (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
.
If the procedure uses more than one parameter, use brackets as in f
:= (x, y) > x^2 + y^2
. Cf. Example 1.
The procedure declaration (x1, x2, ...) > body
is
equivalent to fp::unapply(body, x1, x2, ...)
. The
difference from the other definitions is that body
is evaluated before
defining the procedure. Cf. Example 2.
Note:
The evaluation of 
A MuPAD^{®} procedure may have an arbitrary number of parameters. For each parameter, a default value may be specified. This value is used if no actual value is passed when the procedure is called. E.g.,
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 3.
For each parameter, a type may be specified. This invokes an automatic type checking when the procedure is called. E.g.,
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 4. Checking the input
parameters should be a standard feature of every procedure. See Testing Arguments.
Also an automatic type checking for the return value may be
implemented specifying returntype
. Cf. Example 4.
With the keyword 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 5.
With the keyword option
, special features
may be specified for a procedure:
escape
Must be used if the procedure creates and returns a new procedure
which accesses local values of the enclosing procedure. Cf. Example 6. This option should only be used
if necessary. Also refer to Pref::warnDeadProcEnv
.
hold
Prevents the procedure from evaluating the actual parameters it is called with. See Example 7.
noDebug
Prevents the MuPAD source code debugger from entering this
procedure. Also refer to Pref::ignoreNoDebug
.
Cf. Example 8.
noFlatten
Prevents flattening of sequences passed as arguments of the procedure. See Example 9.
remember
Instructs the procedure to store each computed result in a socalled remember table. When this procedure is called later with the same input parameters, the result is read from this table and needs not be computed again.
This may speed up, e.g., recursive procedures drastically. Cf. Example 10. However, the remember table may
grow large and use a lot of memory. Furthermore, the usefulness of
this function is very limited in the light of properties—identification
of "the same input parameters" does not depend on assumptions on identifiers
or global variables such as DIGITS
and ORDER
, so the returned
result may not be compatible with new assumptions. Use of prog::remember
instead
of this option is highly recommended for any function accepting symbolic
input.
noExpose
Instructs MuPAD to hide the procedure body from the user. Note that this prevents debugging the procedure, too. Cf. Example 15.
With the keyword local
, the local variables
of the procedure are specified, e.g.,
f := proc(...) local x, y; begin body end_proc
.
Cf. Example 11.
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
.
With the keyword 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 12.
One can define procedures that accept a variable number of arguments.
E.g., one may declare the procedure without any formal parameters.
Inside the body, the actual parameters the procedure is called with
may be accessed via the function args
. Cf. Example 13.
Calling a procedure name f
, say, usually
does not print the source code of the body to the screen. Use expose(f)
to
see the body. Cf. Example 14.
The environment variable MAXDEPTH
limits the "nesting depth" of
recursive procedure calls. The default value is MAXDEPTH
= 500.
Cf. Example 10.
If a procedure is a domain slot,
the special variable 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
.
Instead of end_proc
, also the keyword end
can
be used.
The imperative declaration proc  end_proc
internally
results in a call of the kernel function _procdef
.
There is no need to call _procdef
directly.
When evaluating a procedure, MuPAD parses the entire procedure
first, and only then executes it. If you want to introduce a new syntax
(for example, define a new operator
),
do it outside a procedure. See Example 16.
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)
f := n > isprime(n) and isprime(n + 2): f(i) $ i = 11..18
The following command maps an "anonymous" procedure to the elements of a list:
map([1, 2, 3, 4, 5, 6], x > x^2)
delete f:
The declaration of procedures with the "arrow operator" is a powerful tool. In some situations, however, it results in potentially unexpected results:
f := x > sin(x^2)
g := x > f'(x)
The reason is simple: The body of a procedure definition is not evaluated at the time of definition. For those occasions where evaluation is desired, the long version of the arrow operator should be used:
g := x > f'(x)
Of course, in this example, there is an even shorter way:
g := 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)
No default value was declared for the first argument. A warning is issued if this argument is missing:
f()
Warning: Uninitialized variable 'x' is used. Evaluating: f
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: The object '1' is incorrect. The type of argument number 1 must be 'Type::PosInt'. Evaluating: f
Error: Wrong type of 1. argument (type 'Type::PosInt' expected, got argument '1'); Evaluating: 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: The return value '3/2' is incorrect. The type of the return value must be 'Type::Integer'. Evaluating: f
Error: Wrong type of return value (type 'Type::Integer' expected, value is '3/2'); Evaluating: 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)
Also error messages use this name:
f(0)
Error: Division by zero. [_invert] Evaluating: 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)
f(0)
Error: Division by zero. [_invert] Evaluating: 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' is used. Evaluating: g
Error: The operand is invalid. [_power] Evaluating: g
The 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)
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)
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)
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:
Create a procedure that accepts two arguments and returns a table containing the arguments:
f := proc(x, y) begin table(x = y) end_proc:
The parameters x, y
of the procedure f
form
a sequence. If you call this procedure for the sequence (a,
b)
and a variable c
, MuPAD flattens
the nested sequence ((a, b), c)
into (a,
b, c)
. The procedure f
accepts only two
arguments. Thus, it uses a
and b
,
and ignores c
:
f((a, b), c)
When you use the noFlatten
option, MuPAD does
not flatten the arguments of the procedure:
g := proc(x, y) option noFlatten; begin table(x = y) end_proc: g((a, b), c)
For further computations, delete f
and g
:
delete f, g:
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)
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)
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)
Due to the recursive nature of f
, the arguments
are restricted by the maximal recursive depth (see MAXDEPTH
):
f(1000)
Error: Recursive definition: the maximal depth for nested procedure calls is reached. Evaluating: f
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)
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
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
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)
The value of DIGITS
was not changed by the call to myfloat
:
DIGITS
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)
Because of save x
, the previously assigned
value of x
is restored after the integration:
x
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)
f(1, 2, 3, 4, 5, 6, 7)
delete f:
Use expose
to
see the source code of a procedure:
f := proc(x = 0, n : DOM_INT) begin sourceCode; end_proc
expose(f)
proc(x = 0, n : DOM_INT) name f; begin sourceCode end_proc
delete f:
The option noExpose
prevents users from reading
the definition of a procedure:
f := proc(a) option noExpose; begin print(sin(a)); if is(a>1)=TRUE then cos(a) else cos(a + 2) end_if end_proc
f(x), f(0), f(3)
expose(f)
proc(a) name f; option noDebug, noExpose; begin /* Hidden */ end_proc
As you can see, setting option noExpose
implicitly
sets the option noDebug
, too.
For more information on the intended use of this option, refer
to the documentation of write
.
When you evaluate a procedure, MuPAD parses the entire
procedure, and only then executes it. Thus, you cannot define and
use a new operator inside a procedure. For example, when MuPAD parses
this procedure, it does not recognize the new operator <<
.
The reason is that the procedure is not executed yet, and therefore,
the new operator is not defined:
f := proc(A, B) begin bitshiftleft := (a, b) > a * 2^b: operator("<<", bitshiftleft, Binary, 950): C := A<<B; end_proc:
Error: Invalid input. 'expression' is expected. [line 6, col 10]
Define the operator <<
on the interactive
level:
bitshiftleft := (a, b) > a * 2^b: operator("<<", bitshiftleft, Binary, 950):
Now you can use <<
inside procedures
on the interactive level:
f := proc(A, B) begin C := A<<B; end_proc: f(2, 1)
m<<n

The formal parameters of the procedure: identifiers 

Default values for the parameters: arbitrary MuPAD objects 

Admissible types for the parameters: type objects as accepted
by the function 

Admissible type for the return value: a type object as accepted
by the function 

The name of the procedure: an expression 

Available options are: 

The local variables: identifiers 

Global variables: identifiers 

The body of the procedure: an arbitrary sequence of statements 
Procedure of type DOM_PROC
.
args
 context
 debug
 expose
 fp::unapply
 hold
 MAXDEPTH
 newDomain
 Pref::ignoreNoDebug
 Pref::typeCheck
 Pref::warnDeadProcEnv
 return
 save
 testargs