Chains in Klink
As I mentioned in the previous post, Klink is a hybrid of C functions
and a dispatch loop (
_klink_cycle). The dispatch loop finds a
"next" C-based combiner and runs it. This can be an applicative or an
operative. Under the hood, operatives come in several C types.
About a week ago, I added chains to this set. Chains are really a vector of combiners. Evaling a chain queues all those combiners to run, then continues to them with the value it was passed.
Store and load
In order to make this work neatly, I also added two other new types of
T_LOAD. Those are only available
"under the hood" for optimization, because they know things about the
stack that shouldn't be exposed.
T_STORE destructures the current value and stores on the stack a
vector of the resulting objects.
T_LOAD builds a tree from recent values according to a template.
"Leaves" of the tree index an element from a stored vector. That's a
slight simplification: Leaves can also be constants, which are used
About the stored vectors
These stored vectors collectively are somewhat like an environment in that they retain and retrieve values. But unlike the environment, they are distinct across distinct continuations that have yet to assign to them. In other words, if you use this mechanism to capture a combiner's return value, and then before using that value, you re-enter and capture it again, the new return value will not overwrite the old return value, nor vv. Both will be available in their respective continuations.
These stored vectors expire a certain number of frames down the stack, at the bottom of the chain. That keeps them from confusing other chains and keeps the vectors from hanging around uselessly forever.
At the moment,
T_LOAD treats pairs of type (integer . integer)
specially, as indexes. I should clean this up by making a dedicated
type for indexes.
T_STORE may supersede
T_CURRIED, a type of
operative that combines current value with stored data in various
possible ways. In order to do that,
T_LOAD will have to can access
the current value.
Eventually I may switch to a more linear spaghetti stack. Then I will have to change the indexing scheme from (integer . integer) to single integer.
I said earlier the stored vectors were somewhat like an environment but different. Eventually I'd like to use essentially this mechanism to optimize well-behaved environments, so we can index rather than always looking up a symbol. Those in contrast would have to be capturable by continuations. They would also need special care in cases where the environment is captured at some point - either skip those cases or make this data part of environments.
Originally instead of
T_LOAD, I used special
instructions that were assign values when the chain was run. This
proved complex and difficult to work with.