process
The contextual keyword process
specifies the type of a user-defined function.
‘def process funname (params) with’, process definition
The modifier process
indicates that the function sequentially processes its vector arguments, all while maintaining internal state.
table T = with
[| as N, as X |]
[| 0, 1 |]
[| 1, 2 |]
[| 2, -1 |]
def process sumOfSquares(x : number) with
keep sum = 0
sum = sum + x * x
return sum
T.CumulativeSum = sumOfSquares(T.X) scan T.N
total = sumOfSquares(T.X) sort T.N
show table "" with T.N, T.X, T.CumulativeSum
// 6
show scalar "" with total
The first show
statement results in the following table:
N | X | CumulativeSum |
---|---|---|
0 | 1 | 1 |
1 | 2 | 5 |
2 | -1 | 6 |
In our example, the keywords used to invoke sumOfSquares
are scan
and sort
. The scan
keyword feeds sumOfSquares
with T.X
values according to the order of T.N
, namely: first 1
, then 2
, and finally -1
. As a result, we obtain a vector containing all the steps of computation:
sum = 0 + 1 * 1 = 1
sum = 1 + 2 * 2 = 5
sum = 5 + (-1) * (-1) = 6
At each step, the internal state sum
(introduced by the keep
keyword) has a definite value: it is 0
at the beginning, 1
after the first step, 5
after the second step, and 6
after the third step.
Following the explanation above, the sort
keyword acts in the same way as scan
, but instead of returning a vector of results, it only returns the final value of sum
, which is 6
. Therefore, the total
variable is not a vector but a mere scalar, which we print with show scalar
.
Vector arguments can be comma-separated. For example, if we wanted to sum the squares of two numbers, we would define the function as follows:
table T = with
[| as N, as X, as Y |]
[| 0, 1, 4 |]
[| 1, 2, 5 |]
[| 2, 3, 6 |]
def process sumOfSquares(x : number, y : number) with
keep sum = 0
sum = sum + x * x + y * y
return sum
total = sumOfSquares(T.X, T.Y) sort T.N
// 91
show scalar "" with total
The computation would then proceed as follows:
sum = 0 + 1 * 1 + 4 * 4 = 17
sum = 17 + 2 * 2 + 5 * 5 = 46
sum = 46 + 3 * 3 + 6 * 6 = 91
On the other hand, if wanted to initialize sum
with a specific value, we would pass it as an additional argument after a semicolon (;
):
table T = with
[| as N, as X |]
[| 0, 1 |]
[| 1, 2 |]
[| 2, -1 |]
def process sumOfSquares(x : number; seed : number) with
keep sum = seed
sum = sum + x * x
return sum
total = sumOfSquares(T.X; 5) sort T.N
// 11
show scalar "" with total
This will be computed as follows:
sum = 5 + 1 * 1 = 6
sum = 6 + 2 * 2 = 10
sum = 10 + (-1) * (-1) = 11
Of course, it is also possible to use multiple vector arguments and multiple initialization arguments at the same time, as the following example demonstrates:
table T = with
[| as N, as X, as Y |]
[| 0, 1, 4 |]
[| 1, 2, 5 |]
[| 2, 3, 6 |]
def process sumOfSquares(x : number, y : number; seedX : number, seedY : number) with
keep sum = seedX + seedY
sum = sum + x * x + y * y
return sum
total = sumOfSquares(T.X, T.Y; 5, 10) sort T.N
// 106
show scalar "" with total
The computation proceeds similarly to the previous examples:
sum = 5 + 10 + 1 * 1 + 4 * 4 = 32
sum = 32 + 2 * 2 + 5 * 5 = 61
sum = 61 + 3 * 3 + 6 * 6 = 106
Finally, what happens if the vector arguments are empty? In this scenario, the process will return the default value of the data type. For example:
table T = with
[| as N, as X |]
[| 0, 1 |]
[| 1, 2 |]
[| 2, -1 |]
def process sumOfSquares(x : number) with
keep sum = 0
sum = sum + x * x
return sum
where T.X > 100
total = sumOfSquares(T.X) sort T.N
// 0
show scalar "" with total
Since where T.X > 100
essentially filters out all the elements of T.X
, the process returns 0
.
However, it is also possible to specify what default return value must be. In the following example, the default return value is explicitly set to 42
:
table T = with
[| as N, as X |]
[| 0, 1 |]
[| 1, 2 |]
[| 2, -1 |]
def process sumOfSquares(x : number) default 42 with
keep sum = 0
sum = sum + x * x
return sum
where T.X > 100
total = sumOfSquares(T.X) sort T.N
// 42
show scalar "" with total