Iterations with FOLD<N>#
FOLD<N> macro makes it possible to implement operations on a list of values such as sum, filter, map, zip, exists, etc. The macro behaves like the fold or reduce function in other programming languages.
FOLD<N>(list, start, foldFunc)
Parameter |
Description |
---|---|
N |
Maximum number of iterations, up to \(1000\). |
list |
List of values. |
start |
Initial value. |
foldFunc |
Combining function. |
The combining function accepts two input parameters: the intermediate result and the next element of the list. Macro FOLD<N>(list, start, foldFunc) means:
Execute up to N iterations.
At each iteration: take the r-esult of the previous iteration (at the first iteration take the start value) and the next list item list, apply the foldFunc function to this pair.
Return the final result.
The value of N must be known in advance. If there are more elements in the list than specified in FOLD, the script fails. The complexity of FOLD<N> corresponds to the complexity of foldFunc multiplied by N plus extras. The FOLD<N> macro is a syntactic sugar; it is unwrapped by the compiler. Therefore, in particular, the size of the script increases linearly with N.
Sum#
func sum(accum: Int, next: Int) = accum + next
let arr = [1,2,3,4,5]
FOLD<5>(arr, 0, sum) # Result: 15
The expression
FOLD<5>(arr, 0, sum)
after compiling and decompiling will look like this:
let $list = arr
let $size = size($list)
let $acc0 = 0
if (($size == 0))
then $acc0
else {
let $acc1 = sum($acc0, $list[0])
if (($size == 1))
then $acc1
else {
let $acc2 = sum($acc1, $list[1])
if (($size == 2))
then $acc2
else {
let $acc3 = sum($acc2, $list[2])
if (($size == 3))
then $acc3
else {
let $acc4 = sum($acc3, $list[3])
if (($size == 4))
then $acc4
else {
let $acc5 = sum($acc4, $list[4])
if (($size == 5))
then $acc5
else {
let $acc6 = sum($acc5, $list[5])
throw("List size exceed 5")
}
}
}
}
}
}
Product#
func mult(accum: Int, next: Int) = accum * next
let arr = [1,2,3,4,5]
FOLD<5>(arr, 1, mult) # Result: 1204]
Filter#
The following code composes an array consisting only of even elements of the original array:
func filterEven(accum: List[Int], next: Int) =
if (next % 2 == 0) then accum :+ next else accum
let arr = [1,2,3,4,5]
FOLD<5>(arr, [], filterEven) # Result: [2, 4]
Map#
The following code inverts the array, reducing each element by \(1\):
func map(accum: List[Int], next: Int) = (next - 1) :: accum
let arr = [1, 2, 3, 4, 5]
FOLD<5>(arr, [], map) # Result: [4, 3, 2, 1, 0]