Previous Page Next Page Contents

proc -- define a procedure

Introduction

proc - 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(...)

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, remember
local1, local2, ... - the local variables: identifiers
global1, global2, ... - global variables: identifiers
body - the body of the procedure: an arbitrary sequence of statements

Returns

a procedure of type DOM_PROC.

Related Functions

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

Details

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

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:

Example 3

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:

Example 4

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:

Example 5

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:

Example 6

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:

Example 7

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 8

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:

Example 9

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 10

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:

Example 11

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 12

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:

Changes




Do you have questions or comments?


Copyright © SciFace Software GmbH & Co. KG 2000