Notes: Stack Operations for String Rewriting

This is a very brief notecard about something I've been working on. This kinda serves as a means of documenting my thoughts and what lead to this synthesis. Skip to Synthesis if you just want the thingy and not the rambling story of getting there. Also, since these are notes, expect them to be pretty messy.

Fusion of Ideas

Relational Machine Calculus

Jon Purdy introduce me to "Relational Machine Calculus". Apparently, AGAIN reminded them of this concept. In the paper it describes a stack machine with multiple named stacks and prolog-style variables that unify with values.

[X]foo foo<3>
Relational Machine Calculus is based on variables which follow Prolog style unification. RMC has multiple stacks [...]foo push to foo and foo<...> pops from foo unifying with the value provided. In this case our toy program unifies X with 3. If I understand the paper correctly.

I don't fully grasp the ideas here. I only really understand the machine presented. The examples don't really illustrate much for me (I feel like I'm missing prior experience / knowledge). They also don't really give an idea of how unification will work mechanically. For me, mechanics matter more than theory-based description. So, I just kinda let it mull about in the back of my mind.

Rejoice (and uxn)

For a while now, I've been mulling over a sequential, stack-based assembly language for Nova. More generally, I've been really trying to describe string rewriting in general using an assembly language for a stack machine. Every attempt has resisted my efforts. Until, Devine release Rejoice which had me thinking about this idea again.

( The forge contains 3 ingots of lead )
lead^3

( Double the amount of ingots, add the philosopher's stone )
lead^lead stone

( The philosopher stone turns four ingots into gold )
'gold/[stone lead^4]

( Inspect the result )
take ."It's " [True Fool]/[take gold]

@Fool  .pyrite.. End
@True  .gold! @End
An example taken from rejoice

It's a concatenative-flavored assembly language for multiset rewriting. "Fractions" like a/x describe a rewriting operation: given x, I'll give you a. I've been struggling to write a clean parser for the language. I tend to prefer LL(k) parsers. Ideally, LL(1) with no need to look ahead. Rejoice's fraction syntax makes that rather hard as you have to scan until you find a / or space before knowing what else to parse.

My frustration with Rejoice syntax eventually lead me to the thought of making the denominator of fractions independent. uxn has this syntax for anonymous "unless blocks": ?{ ( only runs if the top-of-stack is 0 ) }. So, I thought, why not borrow this, invert the condition, and make my machine "signal failure". So, something like a/x becomes /x { a }. "Attempt to take x. If that succeeded, give a". That immediately resolved my parsing issues, but also lead to synthesizing a new idea.

Synthesis

Move and Unify, or Fail

The core of the idea was a multistack machine based on symbol unification. Unification would be described by the following actions:

The Operations

The core operations are as followed using a notation I came up with.

$foo
Push value from current stack, to foo
!foo
Pop value from foo to current stack
&foo
Peek value from foo to current stack
~foo
Unify top of current stack with foo using above method

Each of these operations can fail. When they do, the interpreter shall set a flag that conditional blocks can observe. Additionally, these are the only push, pop, peek, and unify can fail. Everything else always succeeds.

Well, unless I find reason for something else to fail. This is all notes

A Contrived Example

Lets give this language some additional pieces of syntax: the aforementioned {}, @Label to mark an address to jump to, \Label to preform an unconditional jump, and %add for an addition operation. We can describe a loop that counts up to ten as followed:

10 $stop-at 0 @Count
    ~stop-at { \Done }
    1 %add \Count
@Done
A toy program that does nothing but iterate to 10, then jumps to the end of the program

First, we move 10 onto the target stack. Then we push 0 to the current stack. Next we mark the start of our loop (@Count). ~target { |Done } attempts to unify the top of the current stack with target this will only succeed once we've counted to ten. 1 %add \Count begines the next iteration of this loop.

I think this gives me the basis of a stack-machine that can describe string rewriting nicely. Currently working on implementing small assembly and interpreter. It's current named Squirm just cause I couldn't think of anything better.