## User-defined Functions

There are several methods of creating user-defined functions. Single line functions can be specified with the #deffun command in the following format:

#deffun name(arg1, arg2, arg3, ..., argn) statement

where name is a string that identifies the function and arg is any number of arguments to the function. The body of the function is specified by statement and typically consists of one or more expressions that incorporate the function arguments. For example:

#deffun normal(s) s/max(s)

A function is invoked by referring to the function name and appropriate arguments.

normal(W1)

If a functions does not accept arguments, the argument list is omitted.

#deffun minmax max-min

SPL function names are not case sensitive.

Multi-line functions must be specified in separate ASCII files typically with the same name as the function and the .spl extension. The #deffun keyword is optional for functions defined in a file. The function body must be enclosed in { }. The argument list, if any, must be enclosed in ( ) and immediately follow the function name.

/* normal.spl */

normal(s)

{

s / max(s);

}

Here's an example of a function that creates a series consisting of the Fibonacci numbers:

// Fibonacci numbers returned as series

fib(x)

{

local a, b, c, j, sig[];

a = 0;

b = 1;

j = 1;

while(b < x)

{

c = b;

b = a + b;

a = c;

sig[j] = a;

j = j + 1;

}

return(sig);

}

A more compact example of generating the Fibonacci numbers:

// compact Fibonacci example

fib2(n)

{

local j = 1, f[] = {1, 1};

while (f[j] + f[j+1] < n)

{

f[j+2] = f[j] + f[j+1];

j = j + 1;

}

return(f);

}

Finally, a very fast Fibonacci implementation:

// fast Fibonacci

fastfib2(n)

{

local a, b, c, f;

a = sqrt(5);

b = (1+a) / 2;

c = -1 / b;

f = (b^n - c^n) / a;

return(f);

}

A user defined function is automatically loaded and invoked if the function name is the same as the file name with extension .spl. An SPL file may contain more than one function.

Functions can be recursive. For example:

// recursive Fibonacci

recurfib(n)

{

if (n < 2) return(n);

else return(fib(n - 1) + fib(n - 2));

}

// factorial function

fac(x)

{

if (x <= 0) return(1);

else return(x * fac(x-1));

}

A function argument is optional if it is not referenced when the function is invoked.

func1(x, y)

{

if (x < 0) return(y);

else return(x);

}

func1(1)

1

func1(-1)

y: Unknown Variable

The argc variable indicates the actual number of input arguments a function is called with.

func1(x, y)

{

if (argc < 2) y = 10;

if (x < 0) return(y);

else return(x);

}

func1(-1)

returns 10.

The outargc variable indicates the number of variables that a function will assign.

The ITERATE modifier creates an SPL function that automatically iterates over each column of an input array.

ITERATE minscale(x)

{

return(x / min(x));

}

a = {{1, 2, 3},

{4, 5, 6},

{7, 8, 9}};

b = minscale(a);

b == {{1, 1, 1},

{2, 2, 2},

{3, 3, 3}}

Because minscale is declared as an ITERATE function, it automatically iterates through each column of the input array one at a time. Since each iteration only receives a single column of the original input, the minimum is calculated as the minimum of the current column. Thus, mincale behaves as:

x / colmin(x)