Antiforms
An antiform is a variant of a value that can’t be put in a list. It carries the same payload as the ordinary value, but it exists to be a signal rather than data: “nothing here”, “splice these”, “this failed”, “here are several results”. Because an antiform can’t end up inside a block by accident, code that doesn’t know about the signal can’t mistake it for data.
Eight fundamental types have antiforms, each with its own meaning:
| Antiform | Of | What it signals |
|---|---|---|
LOGIC! | WORD! | ~okay~ and ~null~: true, and the one false |
SPLICE! | BLOCK! | items to be spliced into a list, not added as one |
DATATYPE! | FENCE! | the type of a value |
ACTION! | FRAME! | a function that runs when its word is evaluated |
VOID! | BLANK! | no value |
TRASH! | TAG! | an unusable value, with a note saying why |
PACK! | GROUP! | several results at once |
FAILURE! | ERROR! | an error that must be dealt with |
How They Look
The console shows an antiform between backslashes, with a comment giving its type. The notation inside the backslashes is the antiform’s quasiform: the same payload with tildes around it.
>> spread [a b]
== \~[a b]~\ ; antiform (splice!)
>> null
== \~null~\ ; antiform (logic!)
>> type of 1
== \~{integer!}~\ ; antiform (datatype!)
Quasiforms, LIFT, and UNLIFT
An antiform can’t go in a list, but its quasiform can. Evaluating a quasiform gives the antiform back:
>> first [~[a b]~]
== ~[a b]~
>> ~[a b]~
== \~[a b]~\ ; antiform (splice!)
LIFT turns any value into something that can be stored: antiforms become quasiforms, and everything else gains a level of quoting. UNLIFT undoes it exactly. So a signal can be put into “suspended animation” in a list, and brought back later:
>> lift spread [a b]
== ~[a b]~
>> lift 1
== '1
>> unlift first [~[a b]~]
== \~[a b]~\ ; antiform (splice!)
>> unlift first ['1]
== 1
This one pair of operations works for every antiform, current and future, which is the reason antiforms are a general mechanism rather than a collection of special types.
Stable and Unstable
Antiforms come in two grades.
Stable antiforms (LOGIC!, SPLICE!, DATATYPE!, ACTION!) can be held in a variable and passed as an argument. They just can’t be put in a list.
>> s: spread [a b]
== \~[a b]~\ ; antiform (splice!)
>> append [x] s
== [x a b]
>> reduce [null]
** PANIC: Invalid use of ~null~ antiform
Unstable antiforms (VOID!, TRASH!, PACK!, FAILURE!) can’t even be held in a variable. Assigning one either decays it to a stable value (a PACK! becomes its first item), unsets the variable (VOID!), or errors (FAILURE!). They have to be dealt with where they are produced, or LIFTed first.
>> p: pack [1 2]
== \~('1 '2)~\ ; antiform (pack!)
>> p
== 1
>> x: fail "oops"
** Failure: oops
The practical consequence: anything that can sit in a variable can be tested by IF without special handling, because the antiforms that can’t be tested are exactly the ones that can’t sit in a variable.
Telling Them Apart
>> antiform? spread [a]
== \~okay~\ ; antiform (logic!)
>> element? spread [a]
== \~null~\ ; antiform (logic!)
>> element? 1
== \~okay~\ ; antiform (logic!)
>> any-stable? spread [a]
== \~okay~\ ; antiform (logic!)
>> quasiform? first [~[a]~]
== \~okay~\ ; antiform (logic!)
>> type of first [~[a]~]
== \~{quasiform!}~\ ; antiform (datatype!)
To ask which fundamental type an antiform came from, lift it, take the quasi off, and ask that:
>> type of unquasi lift spread [a]
== \~{block!}~\ ; antiform (datatype!)
>> type of unquasi lift null
== \~{word!}~\ ; antiform (datatype!)
Why
The design argument, and the history of how the eight came to be the eight, is on the forum rather than here:
- A Justification of Generalized Isotopes (2022, kept current) – why one lift/unlift mechanism beats a pile of special types, starting from the old
APPEND/ONLYproblem. (“Isotopes” was the earlier name for antiforms and quasiforms together.) - Which Antiforms Are In Use? (2024, kept current) – the table above, and a history of which type each antiform has been attached to over time.
Table of contents
- LOGIC! - either ~okay~, or ~null~ (the only "falsey" state)
- SPLICE! - fragment of multiple values without a surrounding container
- DATATYPE! - the type of a value expressed as an antiform
- ACTION! - will trigger function execution from words
- VOID! - panics on WORD! access, multi-step evaluations discard
- TRASH! - panics on WORD! access, console does not display
- PACK! - multi-return that decays to first item, empty is HEAVY VOID
- FAILURE! - failure state that is escalated to a panic if not triaged