Arithmetic operations: + - * / mod ^ floor sin cos exp log atan
Bitwize logic operations and or xor not
Finite array traversal with accumulator and array output: loop
Scheme language forms: define lambda let let* let-values let*-values values
Standard Scheme forms for unrolled Metaprogramming
#lang s-exp rai/stream (define (square x) (* x x)) (define (cube x) (let ((sq (square x))) (* sq x)))
The loop construct is a combination of map style list to list and fold style list to scalar operations. This primitive closely resembles the feedback mechanism for the time dimension.
As an illustration consider a program that takes an input array and computes the accumulated array.
#lang s-exp rai/stream (define (sum xs) (let-values* (((accu-out array-out) ;; accumulators and output arrays (loop (i (n 3)) ;; loop index and array length ((accu 0)) ;; accumulators ((x xs)) ;; input element binding (let* ((sum (+ acc x)) (out sum)) (values sum ;; accumulator out out))))) ;; array element out array-out))
Since the language is pure, the if operator is a function, and there is a lot of freedom on how to implement it.
In the low-level implementation used in C code generation, the computations in both branches are executed. Only the resulting value is selected based on the condition. This approach allows the language semantics to be mapped to data-parallel processing such as CPU SIMD instructions or GPU shaders.
Note that this choice prevents the use of direct recursion in the DSL. Recursion is currently not prevented, and will cause infinite loops. For the application domain, the need for recursion is mostly eliminated by the presence of the loop construct.