RiX at a glance
RiX uses familiar expression syntax, then adds notation for ideas that mathematical programs routinely need: exact values, intervals, structured collections, explicit data flow, units, semantic types, and controlled evaluation.
Exact values first
1/3 + 1/6; ## 1/2
1..3/4; ## mixed number: 7/4
0.#3; ## repeating decimal: 1/3
2:5; ## rational interval
1.23[56:67]; ## appended bounds: 1.2356:1.2367
1.23[+5:-6]; ## last-place offsets: 1.17:1.28
1.2[+-0.1]; ## symmetric offset: 1.19:1.21
RiX delegates its foundational exact arithmetic to RatMath core types. Approximation is an explicit extension boundary rather than the default numeric model.
Certified uncertainty stays exact
23.456?; ## certified prefix; enclosure 23.456:23.457
23.456?789; ## 789 is provisional, not part of the guarantee
3.~7~15?; ## a continued-fraction cylinder, not an exact finite CF
(1/7).ToDecimalApproximation(5); ## 0.14285?
(1/97) ~> ".12"; ## certified bounded conversion
Every such value carries exact rational endpoints. Arithmetic propagates the enclosure, while comparisons may produce the undecided decision ?:
decision := 23.456? < 23.4565;
decision ?: "yes" ?_ "no" ?? "needs refinement";
Here 1 is truth, _ is a decided negative/null result, and ? means the current information does not decide the question. It is not treated as truth by filters, guards, assertions, cases, or loops.
Unsigned bracket values append digits to a decimal. Signed values are offsets measured in units of the base’s last visible digit: 1.23 uses hundredths, while 1.2 uses tenths. Thus 1.23[+5:-6] adds 5 × 0.01 and subtracts 6 × 0.01; 1.2[+-0.1] applies 0.1 × 0.1 = 0.01 in both directions. When a bracket contains two values, colon is the required separator.
Names reveal intent
Lowercase-leading names are user values. Uppercase-leading names are callable/system-facing values. Adjacency can therefore read mathematically:
x := 7;
Sq(x) -> x^2;
3x^2; ## 3 * x^2
Sq 3x; ## Sq(3*x)
Explicit calls are always available. The case convention helps the parser distinguish mathematical multiplication from application.
Functions can prepare their inputs
Positive(x) ?- [x > 0] -> x;
Nonzero(x) ?!- [x != 0] -> x;
?- is a soft preparation gate: failure means “this function does not accept that candidate.” ?!- is strict and propagates failure. ??- additionally lets undecided fall through; ??!- throws unless the guard is decided and successful. Ordered variants combine into multifunctions, letting dispatch be written in RiX rather than hidden in host code.
For an expected rejection that deserves a result, use check ?_> diagnostic on decided negative/null, or check ??> diagnostic on undecided. These return from the active function call, including from prep or a nested block, rather than selecting another variant. They are errors outside a call. See diagnostic guards and early returns.
Containers announce what they are
[1, 2, 3]; ## array
{| 1, 2, 3 |}; ## set
{= name = "Ada" }; ## map
{: 2, 3 }; ## tuple
{:2x2: 1, 2; 3, 4 }; ## tensor
{; x := 2; x^3 }; ## execution block
{? x > 0 ? x; -x }; ## case
The brace sigil is a compact type marker. A reader can tell a block, map, set, tuple, tensor, loop, case, mutation, or symbolic specification apart at its opening delimiter.
Pipes make traversal visible
Double(x) -> 2x;
Positive(x) -> x > 0;
[1, -2, 3] |>> Double; ## map
[1, -2, 3] |>? Positive; ## filter
[1, 2, 3] |>: @+[2]; ## reduce
Traversal callbacks can receive (value, locator, source). The locator is a one-based index for sequences, a key for maps, and an index tuple for tensors.
Generators can stay lazy
finite := [1, |+ 2, |; 6];
lazy := [1, |+ 2, |^ 6];
firstFive := [1, |+ 1, |^ _][1:5];
Generator clauses describe seeds, recurrence/history, transforms, filters, and stopping. Lazy sequences compute and cache only what a consumer asks for.
Units and exact generators compose
distance := 120~[m];
elapsed := 30~[s] + 2~[min];
speed := .ConvertUnit(distance / elapsed, "m/s");
z := 1 + 1~{i};
c := .Complex.Cayley(z);
c.Cartesian();
Scientific unit sugar (~[...]) resolves through the configurable .Units collection. Mathematical/exact generator sugar (~{...}) resolves through .Exact. Both participate in ordinary arithmetic dispatch.
Assignment says whether identity matters
RiX variables name cells. Its assignment family makes aliasing and update behavior visible:
| Form | Meaning |
|---|---|
x = y |
alias/rebind; variables can share a cell |
x := y |
fresh cell with a shallow copy |
x ~= y |
replace the value in the existing cell |
x ::= y |
fresh cell with a deep copy |
x ~~= y |
deep-copy into the existing cell |
That distinction matters for mutable structures, metadata, closures, and semantic values. The complete introduction develops the model progressively.
The system object is explicit
.Len([10, 20, 30]);
.Warn("large interval", {= width = 12 });
.Units[:degC](20);
The leading dot is the system capability object. Hosts can construct and freeze it, add capabilities, or withhold groups for imported scripts. Operator functions are first-class too: @+ names addition, and @+[2] caps it to two incoming arguments.
Three ways to keep learning
- Follow the complete introduction when you want concepts and examples in teaching order.
- Use the syntax guide and methods guide while writing code.
- Read the developer guide when embedding or extending the parser/evaluator.