-
Notifications
You must be signed in to change notification settings - Fork 0
Booleans
true and false;
is false. You receive similarly sensible results for or, xor and not, as well as the more esoteric nand, nor and xnor, and comparison operators return boolean values:
10 < 12 and 12 < 14; // true
Evaluation of the binary boolean operators is short circuited appropriately so true or something will not
evaluate something. The exceptions are xor and xnor which must evaluate both their arguments.
The standard comparison operators are available. They require that the types of their arguments agree,
and in F♮ any two data with the same type can be compared (sometimes somewhat arbitrarily, for example false < true.) The operators are:
| op | name |
|---|---|
== |
equal to |
!= |
not equal to |
< |
less than |
> |
greater than |
<= |
less than or equal to |
>= |
greater than or equal to |
Some effort has been made to allow all data to be sortable:
- When comparing user defined types they sort in the order they are declared in, for example
after
typedef color { red | green | blue },red < greenandgreen < blue. - Functions sort (provided they have the same type signature) by their bytecode address.
- Complex numbers do not have a well defined sort order in certain edge cases so I've imposed a fairly arbitrary "tie breaking" mechanism, discussed below.
Other than the true boolean comparison operators, there's also a "spaceship" binary comparison
operator <=>, borrowed from Perl, which returns one of three values: lt, eq or gt.
This is obviously more efficient, especially when comparing
deeply nested structures, and works well with a switch statement:
switch (a <=> b) {
(lt) { do stuff if a < b }
(eq) { do stuf if a == b }
(gt) { do stuff if a > b }
}
The spaceship operator implementation as you might expect is actually used by all the other comparison operators. As mentioned above this is fairly straightforward for most types, but complex numbers are points on a plane and have no well-defined linear sequence. To allow deterministic sorting anyway, the implementation uses a geometric tie-break strategy.
For a complex number
and compare keys lexicographically.
Equivalent pseudocode:
let ax = com_real(a);
let ay = com_imag(a) / 1i;
let bx = com_real(b);
let by = com_imag(b) / 1i;
switch ((ax + ay) <=> (bx + by)) {
(lt) { lt }
(gt) { gt }
(eq) {
switch (ax <=> bx) {
(lt) { lt }
(eq) { eq }
(gt) { gt }
}
}
}
This is equivalent to the current implementation:
switch(com_real(a) <=> com_real(b), com_imag(a) / 1i <=> com_imag(b) / 1i) {
(lt, lt) { lt }
(lt, eq) { lt }
(lt, gt) { compare_magnitudes(a, b) }
(eq, lt) { lt }
(eq, eq) { eq }
(eq, gt) { gt }
(gt, lt) { compare_magnitudes(a, b) }
(gt, eq) { gt }
(gt, gt) { gt }
}
where compare_magnitudes is
switch(com_real(a) + com_imag(a) / 1i <=> com_real(b) + com_imag(b) / 1i) {
(lt) { lt }
(eq) { if (com_real(a) < com_real(b)) { lt } else { gt } }
(gt) { gt }
}
A picture should help:

Intuition: lines of constant
$x+y$ have slope$-1$ . First compare which line each point is on. If both points are on the same line, compare$x$ to break the tie. The tie-break axis is arbitrary, but fixed, so the ordering is deterministic and consistent.
This is not part of the current language, but the same pattern can be reused later if vectors are introduced.
For
lexicographically (after validating equal dimensions).
That keeps the same design principle:
- compare by a projection (the sum),
- break ties by a fixed coordinate order.
Whether vectors should be in the numeric tower or a separate type family is still an open design choice.
Next: Conditionals

CEKF(s) a.k.a. F Natural a.k.a F♮