Documentation

# `->`, `-->`, `proc`, `name`, `option`, `local`, `begin`, `end_proc`, `procname`

Define a procedure

MuPAD® notebooks will be removed in a future release. Use MATLAB® live scripts instead.

MATLAB live scripts support most MuPAD functionality, though there are some differences. For more information, see Convert MuPAD Notebooks to MATLAB Live Scripts.

## Syntax

```( 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

( x1, x2, … ) --> body
_procdef(`, …`)
```

## Description

`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 `body` must not contain references to parameters or local variables of an outer procedure.

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 so-called 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.

## Examples

### Example 1

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:`

### Example 2

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'`
` `

### Example 3

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:`

### Example 4

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: Invalid object '-1'. 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: Invalid return value '3/2'. It must be of type 'Type::Integer'. Evaluating: f ```
```Error: Wrong type of return value (type 'Type::Integer' expected, value is '3/2'); Evaluating: f ```
`delete f:`

### Example 5

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:`

### Example 6

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: Invalid operand. [_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:`

### Example 7

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:`

### Example 8

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:`

### Example 9

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:`

### Example 10

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: Reached maximal depth for nested procedure calls. 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:`

### Example 11

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:`

### Example 12

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:`

### Example 13

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:`

### Example 14

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:`

### Example 15

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`.

### Example 16

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. Expected 'expression'. [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`
` `

## Parameters

 `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`, `noExpose`, `noFlatten`, `remember` ```local1, local2, …``` The local variables: identifiers `global1, global2, …` Global variables: identifiers `body` The body of the procedure: an arbitrary sequence of statements

## Return Values

Procedure of type `DOM_PROC`.

#### Mathematical Modeling with Symbolic Math Toolbox

Get examples and videos