Effects, modalities, and definers¶
Monadically, does nothing.
Returns a fuse that fuses monadic computations by creating a monadic computation that executes them both.
This is a fuse, not a merge, because it’s not necessarily idempotent when performance is taken into account. If a monadic computation is fused with itself this way, the resulting monadic computation may be twice as slow.
Monadically, passes the current modality to the given monadic callback in the same tick.
A modality must be passed to certain effectful primitives as a way to give the effects something to be deterministic by. (The terms “mode” and “modality” might be idiosyncrasies of Cene. A more standard term is “world-passing style.”)
Returns (nil). The given modality must be the current one. If it isn’t, this causes an error.
Monadically, executes the given monadic computation in a later tick.
This is useful mainly for concurrency. It allows the given computation to depend on values that might not be available right now.
Monadically, creates a new uninitialized piece of state, and calls a monadic callback in a later tick with a getdef that retrieves and defines the value of that state.
Rationale: Cene expressions are designed so they can have consistent performance each time they run. Therefore, algorithms written as Cene expressions cannot rely on laziness or JIT techniques (even though an implementation of Cene may in fact implement such things as optimizations). However, laziness is useful to reduce the amortized computational complexity of data structures like finger trees, which are good for representing strings. To support this data structure technique, Cene offers make-promise-later, a standard way to allocate promise state even from a computation that has no other access to state.
Not all Cene modalities will necessarily support the make-promise-later side effect. However, the macroexpansion and unit test modalities do, and that’s everything for now.
A value that indicates a function
get that takes a mode and obtains a value, along with indicating a definer
def to determine that value.
definer dex value
Monadically, checks whether the given value satisfies the given dex, and writes to the given definer with the dex and the value either way. If two definitions are written to the same dex, then they must have the same dex and value, and the value must satisfy the dex, or there’s an error. The dex serves no purpose other than to verify this.
Implement and use this.
Monadically, executes the effects in a later tick and commits to writing to the given definer in that tick or later.
This is only useful to suppress error messages about the definition not existing if there’s an error in this logical thread.