[ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

## 4.2 Writing user defined functions

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

### 4.2.1 User defined functions

To define functions by an user himself, ‘def’ statement must be used. Syntactical errors are detected in the parsing phase of Asir, and notified with an indication of where Asir found the error. If a function with the same name is already defined (regardless to its arity,) the new definition will override the old one, and the user will be told by a message,

```afo() redefined.
```

on the screen when a flag `verbose` is set to a non-zero value by `ctrl()`. Recursive definition, and of course, recursive use of functions are available. A call for an yet undefined function in a function definition is not detected as an error. An error will be detected at execution of the call of that yet undefined function.

```def f(X) {
if ( !X )
return 1;
else
return X * f(X-1);
}

def c(N)
{
A = newvect(N+1); A[0] = B = newvect(1); B[0] = 1;
for ( K = 1; K <= N; K++ ) {
A[K] = B = newvect(K+1); B[0] = B[K] = 1;
for ( P = A[K-1], J = 1; J < K; J++ )
B[J] = P[J-1]+P[J];
}
return A;
}

{
return A+B;
}
```

In the second example, `c(N)` returns a vector, say `A`, of length `N+1`. `A[I]` is a vector of length `I+1`, and each element is again a vector which contains ICJ as its elements.

References

In the following, the manner of writing Asir programs is exhibited for those who have no experience in writing C programs.

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

### 4.2.2 variables and indeterminates

variables (program variables)

A program variable is a string that begins with a capital alphabetical letter followed by any numbers of alphabetical letters, digits and ‘_’.

A program variable is thought of a box (a carrier) which can contain Asir objects of various types. The content is called the ‘value’ of that variable. When an expression in a program is to be evaluated, the variable appearing in the expression is first replaced by its value and then the expression is evaluated to some value and stored in the memory. Thus, no program variable appears in objects in the internal form. All the program variables are initialized to the value 0.

```[0] X^2+X+1;
1
[1] X=2;
2
[2] X^2+X+1;
7
```
indeterminates

An indeterminate is a string that begins with a small alphabetical letter followed by any numbers of alphabetical letters, digits and ‘_’.

An indeterminate is a transcendental element, so-called variable, which is used to construct polynomial rings. An indeterminate cannot have any value. No assignment is allowed to it.

```[3] X=x;
x
[4] X^2+X+1;
x^2+x+1
[5] A='Dx'*(x-1)+x*y-y;
(y+Dx)*x-y-Dx
[6] function foo(x,y);
[7] B=foo(x,y)*x^2-1;
foo(x,y)*x^2-1
```

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

### 4.2.3 parameters and arguments

```def sum(N) {
for ( I = 1, S = 0; I <= N; I++ )
S += I;
return S;
}
```

This is an example definition of a function that sums up integers from 1 to `N`. The `N` in `sum(N)` is called the (formal) parameter of `sum(N)`. The example shows a function of the single argument. In general, any number of parameters can be specified by separating by commas (‘,’). A (formal) parameter accepts a value given as an argument (or an actual parameter) at a function call of the function. Since the value of the argument is given to the formal parameter, any modification to the parameter does not usually affect the argument (or actual parameter). However, there are a few exceptions: vector arguments and matrix arguments.

Let `A` be a program variable and assigned to a vector value `[ a, b ]`. If A is given as an actual parameter to a formal parameter, say `V`, of a function, then an assignment in the function to the vector element designator `V[1]`, say `V[1]=c;`, causes modification of the actual parameter `A` resulting `A` to have an altered value `[ a c ]`. Thus, if a vector is given to a formal parameter of a function, then its element (and subsequently the vector itself) in the calling side is modified through modification of the formal parameter by a vector element designator in the called function. The same applies to a matrix argument. Note that, even in such case where a vector (or a matrix) is given to a formal parameter, the assignment to the whole parameter itself has only a local effect within the function.

```def clear_vector(M) {
/* M is expected to be a vector */
L = size(M)[0];
for ( I = 0; I < L; I++ )
M[I] = 0;
}
```

This function will clear off the vector given as its argument to the formal parameter `M` and return a 0 vector.

Passing a vector as an argument to a function enables returning multiple results by packing each result in a vector element. Another alternative to return multiple results is to use a list. Which to use depends on cases.

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

The text enclosed by ‘/*’ and ‘*/’ (containing ‘/*’ and ‘*/’) is treated as a comment and has no effect to the program execution as in C programs.

```/*
* This is a comment.
*/

def afo(X) {
```

A comment can span to several lines, but it cannot be nested. Only the first ‘/*’ is effective no matter how many ‘/*’’s in the subsequent text exist, and the comment terminates at the first ‘*/’.

In order to comment out a program part that may contain comments in it, use the pair, `#if 0` and `#endif`. (See section preprocessor.)

```#if 0
def bfo(X) {
/* empty */
}
#endif
```

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

### 4.2.5 statements

An user function of Asir is defined in the following form.

```def name(parameter, parameter,...,parameter) {
statement
statement
...
statement
}
```

As you can see, the statement is a fundamental element of the function. Therefore, in order to write a program, you have to learn what the statement is. The simplest statement is the simple statement. One example is an expression with a terminator (‘;’ or ‘\$’.)

```S = sum(N);
```

A ‘`return` statement’ and ‘`break` statement’ are also primitives to construct ‘statements.’ As you can see the syntactic definition of ‘`if` statement’ and ‘`for` statement’, each of their bodies consists of a single ‘statement.’ Usually, you need several statements in such a body. To solve this contradictory requirement, you may use the ‘compound statement.’ A ‘compound statement’ is a sequence of ‘statement’s enclosed by a left brace ‘{’ and a right brace ‘}’. Thus, you can use multiple statement as if it were a single statement.

```if ( I == 0 ) {
J = 1;
K = 2;
L = 3;
}
```

No terminator symbol is necessary after ‘}’, because ‘{’ statement sequence ‘}’ already forms a statement, and it satisfies the syntactical requirement of the ‘`if` statement.’

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

### 4.2.6 `return` statement

There are two forms of `return` statement.

```return expression;

return;
```

Both forms are used for exiting from a function. The former returns the value of the expression as a function value. The function value of the latter is not defined.

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

### 4.2.7 `if` statement

There are two forms of `if` statement.

```if ( expression )             if ( expression )
statement       and           statement
else
statement
```

The interpretation of these forms are obvious. However, be careful when another `if` statement comes at the place for ‘statement’. Let us examine the following example.

```if ( expression1 )
if ( expression2 ) statement1
else
statement2
```

One might guess `statement2` after `else` corresponds with the first `if ( expression1 )` by its appearance of indentation. But, as a matter of fact, the `Asir` parser decides that it correspond with the second `if ( expression2 )`. Ambiguity due to such two kinds of forms of `if` statement is thus solved by introducing a rule that a statement preceded by an `else` matches to the nearest preceding `if`.

Therefore, rearrangement of the above example for improving readability according to the actual interpretation gives the following.

```if ( expression1 ) {
if ( expression2 ) statement1 else statement2
}
```

On the other hand, in order to reflect the indentation, it must be written as the following.

```if ( expression1 ) {
if ( expression2 ) statement1
} else
statement2
```

When `if` is used in the top level, the `if` expression should be terminated with `\$` or `;`. If there is no terminator, the next expression will be skipped to be evaluated.

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

### 4.2.8 `loop`, `break`, `return`, `continue`

There are three kinds of statements for loops (repetitions): the `while` statement, the `for` statement, and the `do` statement.

• `while` statement
It has the following form.
```while ( expression ) statement
```

This statement specifies that `statement` is repeatedly evaluated as far as the `expression` evaluates to a non-zero value. If the expression 1 is given to the `expression`, it forms an infinite loop.

• `for` statement
It has the following form.
```for ( expr list-1; expr; expr list-2 ) statement
```

This is equivalent to the program

```expr list-1 (transformed into a sequence of simple statement)
while ( expr ) {
statement
expr list-2 (transformed into a sequence of simple statement)
}
```
• `do` statement
```do {
statement
} while ( expression )
```

This statement differs from `while` statement by the location of the termination condition: This statement first execute the `statement` and then check the condition, whereas `while` statement does it in the reverse order.

As means for exiting from loops, there are `break` statement and `return` statement. The `continue` statement allows to move the control to a certain point of the loop.

• `break`
The `break` statement is used to exit the inner most loop.
• `return`
The `return` statement is usually used to exit from a function call and it is also effective in a loop.
• `continue`
The `continue` statement is used to move the control to the end point of the loop body. For example, the last expression list will be evaluated in a `for` statement, and the termination condition will be evaluated in a `while` statement.

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

### 4.2.9 structure definition

A structure data type is a fixed length array and each component of the array is accessed by its name. Each type of structure is distinguished by its name. A structure data type is declared by `struct` statement. A structure object is generated by a builtin function `newstruct`. Each member of a structure is accessed by an operatator `->`. If a member of a structure is again a structure, then the specification by `->` can be nested.

```[1] struct rat {num,denom};
0
[2] A = newstruct(rat);
{0,0}
[3] A->num = 1;
1
[4] A->den = 2;
2
[5] A;
{1,2}
[6] struct_type(A);
1
```
References

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

### 4.2.10 various expressions

Major elements to construct expressions are the following:

• addition, subtraction, multiplication, division, exponentiation
The exponentiation is denoted by ‘^’. (This differs from C language.) Division denoted by ‘/’ is used to operate in a field, for example, `2/3` results in a rational number `2/3`. For integer division and polynomial division, both including remainder operation, built-in functions are provided.
```x+1  A^2*B*afo X/3
```
• programming variables with indices
An element of a vector, a matrix or a list can be referred to by indexing. Note that the indices begin with number 0. When the referred element is again a vector, a matrix or a list, repeated indexing is also effective.
```V[0] M[1][2]
```
• comparison operation
There are comparison operations ‘==’ for equivalence, ‘!=’ for non-equivalence, ‘>’, ‘<’,‘>=’, and ‘<=’ for larger or smaller. The results of these operations are either value 1 for the truth, or 0 for the false.
• logical expression
There are two binary logical operations ‘&&’ for logical ‘conjunction’(and), ‘||’ for logical ‘disjunction’(or), and one unary logical operation ‘!’ for logical ‘negation’(not). The results of these operations are either value 1 for the truth, and 0 for the false.
• assignment
Value assignment of a program variable is usually done by ‘=’. There are special assignments combined with arithmetic operations. (‘+=’, ‘-=’, ‘*=’, ‘/=’, ‘^=’)
```A = 2  A *= 3 (the same as A = A*3; The others are alike.)
```
• function call
A function call is also an expression.
• ++’, ‘--
These operators are attached to or before a program variable, and denote special operations and values.
```A++  the expression value is the previous value of A, and A = A+1
A--  the expression value is the previous value of A, and A = A-1
++A  A = A+1, and the value is the one after increment of A
--A  A = A-1, and the value is the one after decrement of A
```

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

### 4.2.11 preprocessor

he Asir user language imitates C language. A typical features of C language include macro expansion and file inclusion by the preprocessor `cpp`. Also, Asir read in user program files through `cpp`. This enables Asir user to use `#include`, `#define`, `#if` etc. in his programs.

• `#include`
Include files are searched within the same directory as the file containing `#include` so that no arguments are passed to `cpp`.
• `#define`
This can be used just as in C language.
• `#if`
This is conveniently used to comment out a large part of a user program that may contain comments by `/*` and `*/`, because such comments cannot be nested.

the following are the macro definitions in ‘defs.h’.

```#define ZERO 0
#define NUM 1
#define POLY 2
#define RAT 3
#define LIST 4
#define VECT 5
#define MAT 6
#define STR 7
#define N_Q 0
#define N_R 1
#define N_A 2
#define N_B 3
#define N_C 4
#define V_IND 0
#define V_UC 1
#define V_PF 2
#define V_SR 3
#define isnum(a) (type(a)==NUM)
#define ispoly(a) (type(a)==POLY)
#define israt(a) (type(a)==RAT)
#define islist(a) (type(a)==LIST)
#define isvect(a) (type(a)==VECT)
#define ismat(a) (type(a)==MAT)
#define isstr(a) (type(a)==STR)
#define FIRST(L) (car(L))
#define SECOND(L) (car(cdr(L)))
#define THIRD(L) (car(cdr(cdr(L))))
#define FOURTH(L) (car(cdr(cdr(cdr(L)))))
#define DEG(a) deg(a,var(a))
#define LCOEF(a) coef(a,deg(a,var(a)))
#define LTERM(a) coef(a,deg(a,var(a)))*var(a)^deg(a,var(a))
#define TT(a) car(car(a))
#define TS(a) car(cdr(car(a)))
#define MAX(a,b) ((a)>(b)?(a):(b))
```

Since we are utilizing the C preprocessor, it cannot properly preprocess expressions with `\$`. For example, even if `LIST` is defined, `LIST` in the expression `LIST\$` is not replaced. Add a blank before `\$`, i.e., write as `LIST \$` to make the proprocessor replace it properly.

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

### 4.2.12 option

If a user defined function is declared with N arguments, then the function is callable with N arguments only.

```[0] def factor(A) { return fctr(A); }
[1] factor(x^5-1,3);
evalf : argument mismatch in factor()
```

A function with indefinite number of arguments can be realized by using a list or an array as its argument. Another method is available as follows:

```% cat factor
def factor(F)
{
Mod = getopt(mod);
ModType = type(Mod);
if ( ModType == 1 ) /* 'mod' is not specified. */
return fctr(F);
else if ( ModType == 0 ) /* 'mod' is a number */
return modfctr(F,Mod);
}
```
```[0] load("factor")\$
[1] factor(x^5-1);
[[1,1],[x-1,1],[x^4+x^3+x^2+x+1,1]]
[2] factor(x^5-1|mod=11);
[[1,1],[x+6,1],[x+2,1],[x+10,1],[x+7,1],[x+8,1]]
```

In the second call of `factor()`, `|mod=11` is placed after the argument `x^5-1`, which appears in the declaration of `factor()`. This means that the value `11` is assigned to the keyword `mod` when the function is executed. The value can be retrieved by `getopt(mod)`. We call such machinery option. If the option for mod is not specified, `getopt(mod)` returns an object whose type is -1. By this feature, one can describe the behaviour of the function when the option is not specified by if statements. After ‘|’ one can append any number of options seperated by ‘,’.

```[100] xxx(1,2,x^2-1,[1,2,3]|proc=1,index=5);
```

Optinal arguments may be given as a list with the key word `option_list` as `option_list=[["key1",value1],["key2",value2],...]`. It is equivalent to pass the optional arguments as `key1=value1,key2=value2,...`.

```[101] dp_gr_main([x^2+y^2-1,x*y-1]|option_list=[["v",[x,y]],["order",[[x,5,y,1]]]]);
```

Since `getopt()` returns an option list, the optional argument `option_list=...` is useful when we call functions with optional arguments from a function with optional arguments to pass the all optional parameters.

```% cat foo.rr
def foo(F)
{
OPTS=getopt();
return factor(F|option_list=OPTS);
}
```
```[3] load("foo.rr")\$
[4] foo(x^5-1|mod=11);
[[1,1],[x+6,1],[x+2,1],[x+10,1],[x+7,1],[x+8,1]]
```

 [ << ] [ < ] [ Up ] [ > ] [ >> ] [Top] [Contents] [Index] [ ? ]

### 4.2.13 module

Function names and variables in a library may be encapsulated by module. Let us see an example of using module

```module stack;

static Sp \$
Sp = 0\$
static Ssize\$
Ssize = 100\$
static Stack \$
Stack = newvect(Ssize)\$
localf push \$
localf pop \$

def push(A) {
if (Sp >= Ssize) {print("Warning: Stack overflow\nDiscard the top"); pop();}
Stack[Sp] = A;
Sp++;
}
def pop() {
local A;
if (Sp <= 0) {print("Stack underflow"); return 0;}
Sp--;
A = Stack[Sp];
return A;
}
endmodule;

def demo() {
stack.push(1);
stack.push(2);
print(stack.pop());
print(stack.pop());
}
```

Module is encapsulated by the sentences `module` module name and `endmodule`. A variable of a module is declared with the key word `static`. The static variables cannot be refered nor changed out of the module, but it can be refered and changed in any functions in the module. The `static` variables must be declared before the definitions of functions, because the one-path parser of asir automatically assume variables as local variables if there is no declaration for them. A global variable which can be refered and changed in or out of the module is declared with the key word `extern`.

Any function defined in a module must be declared forward with the keyword `localf`. In the example above, `push` and `pop` are declared. This declaration is necessary.

A function `functionName` defined in a module `moduleName` can be called by the expression `moduleName.functioName(arg1, arg2, ...)` out of the module. Inside the module, `moduleName.` is not necessary. In the example below, the functions `push` and `pop` defined in the module `stack` are called out of the module.

``` stack.push(2);
print( stack.pop() );
2
```

Any function name defined in a module is local. In other words, the same function name may be used out of the module to define a different function.

The module structure of asir is introduced to develop large libraries. In order to load libraries on demand, the command `module_definedp` will be useful. The below is an example of demand loading.

```if (!module_definedp("stack")) load("stack.rr") \$
```

It is not necessary to declare local variables in asir. As you see in the example of the stack module, we may declare local variables by the key word `local`. Once this key word is used, asir requires to declare all the variables. In order to avoid some troubles to develop a large libraries, it is recommended to use `local` declarations.

When we need to call a function in a module before the module is defined, we must make a prototype declaration as the example below.

```/* Prototype declaration of the module stack */
module stack;
localf push \$
localf pop \$
endmodule;

def demo() {
print("----------------");
stack.push(1);
print(stack.pop());
print("---------------");
}

module stack;
/* The body of the module stack */
endmodule;
```

In order to call functions defined in the top level from the inside of a module, we use `::` as in the example below.

```def afo() {
S = "afo, afo";
return S;
}
module abc;
localf foo,afo \$

def foo() {
G = ::afo();
return G;
}
def afo() {
return "afo, afo in abc";
}
endmodule;
end\$

[1200] abc.foo();
afo, afo
[1201] abc.afo();
afo, afo in abc
```
References

 [ << ] [ < ] [ Up ] [ > ] [ >> ]

This document was generated on July 15, 2024 using texi2html 5.0.