Skip to Main Content Skip to Search
Product Documentation

procdefine a procedure

proc - end_proc defines a procedure.

→ Examples

Calls:

(x1, x2, ...) ->  body


proc(
     x
1 <= default1> <: type1>,
     x
2 <= default2> <: type2>,
     ...
    ) <
: returntype>
  <
name pname;>
  <
option option1, option2, ...>
  <
local local1, local2, ...>
  <
save global1, global2, ...>
begin
   body
end_proc

(x1, x2, ...) -->  body

_procdef(, ...)

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, remember

local1, local2, ...: 

the local variables: identifiers

global1, global2, ...: 

global variables: identifiers

body

the body of the procedure: an arbitrary sequence of statements

Return Value:

a procedure of type DOM_PROC.

Related Functions:

args, context, debug, expose, fp::unapply, hold, MAXDEPTH, newDomain, Pref::ignoreNoDebug, Pref::typeCheck, Pref::warnDeadProcEnv, return, save, testargs, Type

Details:

The evaluation of body must not contain references to parameters or local variables of an outer procedure.

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)

x^2 + 2*x + 1, y^2 + 2*y + 1, 2*a + 2*b + (a + b)^2 + 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 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)

x -> sin(x^2)

g := x -> f'(x)

x -> D(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)

x -> 2*x*cos(x^2)

Of course, in this example, there is an even shorter way:

g := f'

x -> 2*x*cos(x^2)

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)

[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.
  Evaluating: f

[NIL, 1, 2]

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

f(x), f(x + 1), 0.3333333333, -0.5*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)

myName(x), myName(x + 1), 0.3333333333, -0.5*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' 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)

x^3, y^3, 1000

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)

sin(x) + 2 = 3, 1/2 + 1/3 = 5/6

Procedures using optionhold 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 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

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]
  Evaluating: f

Without optionremember, 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 10

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:

Example 11

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)

0.0, 0.02616405487

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 12

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:

Example 13

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:

Example 14

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

`proc f(a) ... end`

f(x), f(0), f(3)

sin(x)
0
sin(3)
cos(x + 2), cos(2), cos(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 15

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: 'expression' expected. [line 7, 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)

4

m<<n

2^n*m

  


Recommended Products

Includes the most popular MATLAB recorded presentations with Q&A sessions led by MATLAB experts.

 © 1984-2012- The MathWorks, Inc.    -   Site Help   -   Patents   -   Trademarks   -   Privacy Policy   -   Preventing Piracy   -   RSS