Spatial languages: Writing code in 2D

BinRoo1 pts1 comments

Spatial languages: writing code in 2D

I guess expressions don’t really need to read left-to-right on a<br>line.

Why can’t a be written vertically too?

All this time we’ve been writing expressions in 1D space, but what<br>happens when we unlock an extra dimension?

Of course the IDE and parser need to play nicely for all this to<br>work. Even then, what’s the point? Well, let’s take a look at these<br>examples below.

3-arity functions

We don’t really see 3-arity functions written in infix notation<br>much.

For example, in Python (and most other languages), you can<br>and 3+ things at once:

x and y and z

Technically, that’s just composing multiple binary functions<br>together.

Even this shortcut in Python to simplify<br>(a is more of the same thing:

a b c

Now, let me introduce you to a funny little operator I’ve been<br>playing with called andFlip, which motivates the need for a<br>true 3-arity infix notation. First, here’s the definition of the<br>function:

def andFlip(args):<br>if args[0] and args[1]:<br>args[2] = not args[2]<br>return args[2]

It takes 2 inputs and flips the target if both inputs are true.

There’s just no good way to write this with infix notation. But let’s<br>try anyways!

Define @@ to be the infix symbol for the<br>andFlip operator. What does it look like in practice?

Method 1: the standard way

One option is to curry andFlip: the infix<br>@@ takes 2 args and returns a function awaiting the 3rd,<br>like so:

(a1 @@ a2) a3

Yeah, that’s alright. It works. But…

Method 2: the goofy way

Forget what you know about code for a second. If I could flick a<br>magic wand, I’d wish for the 3-arity notation to look like this:

a3<br>a1 @@ a2<br>Might as well make use of the y-axis, right?

It makes chaining so much easier:

t1 = 0<br>t2 = 0

t1 t2<br>(x @@ y) @@ z<br>In the chain, x @@ y toggles t1, and<br>t1 continues the chain t1 @@ z, which toggles<br>t2.

That’s a successful three-way toggle, where all x,<br>y, and z must be true for the target to<br>toggle.

Btw, since we’re working in 2D space now, the following<br>expression,

t1<br>x @@ y<br>is equivalent to:

x @@ y<br>t1<br>Example: my chicken coop door

Consider the automatic door I’ve installed on my chicken coop.

The coop’s automatic door (right) and its<br>controller box

With just a photometer and its internal clock, the microcontroller<br>tracks:

x – the photometer crossed its dusk/dawn threshold

y – the reading has held steady for five minutes

z – the gate has not recently toggled

The door toggles only when all three line up. A passing cloud trips<br>x but never outlasts y, so the door stays<br>put.

The coop’s controller is the same chained expression from above:

t1 = 0<br>t2 = 0

t1 t2<br>(x @@ y) @@ z<br>You might be wondering, why not just write<br>x and y and z? Because then the door would mirror the<br>sensors, swinging right back the moment a condition fades.<br>@@ toggles in place: the door moves once and stays, and the<br>partial answer lands in t1, a scratch bit.

Spatial languages get even more fascinating when we introduce<br>vertical chaining!

Vertical chaining

That mutable variable t1 disqualifies the expression<br>from being called a “pure function”. But can we fake it? Can we reset<br>t1 back, all within the same expression?

I’d like to introduce vertical chaining through two puzzles.

Puzzle 1: reset t1<br>back to 0

As mentioned, in the chaining examples above, the variable<br>t1 is mutable.

Here’s a puzzle: how can we reset it back to 0, so the<br>expression “appears” immutable?

You may be tempted to just append the statement t1 = 0<br>and call it a day, but the goal of the puzzle is to do it all within the<br>same expression.

Give it a shot before you scroll down!

Here’s the answer. Since t1 can be reset by repeating<br>the same thing that was used to toggle it, we can combine expressions<br>into a larger 2D one, like so:

t1 = 0<br>t2 = 0

(x @@ y) @@ z<br>t1 t2<br>(x @@ y)<br>Ok, I’m probably blowing your mind right now.

The data flow is still as you’d expect in a programming language,<br>left-to-right and top-to-bottom. If x and y<br>are true, the first x @@ y flips t1 and then<br>the second x @@ y resets it. Otherwise, both leave<br>t1 untouched.

This puzzle actually models the CCCX gate in quantum<br>computing, where uncomputing the<br>intermediate t1 value within the same circuit is an<br>important requirement.

Puzzle<br>2: reset the temporary variable back to the original value

If t1 starts off with an unknown boolean value<br>n, then it gets more complicated.

t1 = n<br>t2 = 0

t1 t2<br>(x @@ y) @@ z<br>The same trick above to reset t1 back to its original<br>value won’t work.

See for yourself: when t1 = 1 and x,<br>y, and z are all true, then t2<br>remains 0, which is incorrect.

t1 = 1<br>t2 = 0

(1 @@ 1) @@ 1<br>t1 t2<br>(1 @@ 1)<br>So, what’s the answer?

Tada!

t1 = n<br>t2 = 0

t1 t2<br>(x @@ y) @@ z<br>t1 t2<br>(x @@ y) @@ z<br>Absolutely legendary. This single 2D expression resets<br>t1 back to n while producing the correct<br>result for t2.

This puzzle is inspired by the concept of resetting a borrowed ancilla in<br>quantum computing. t1 is the “borrowed” or “dirty” value<br>that remains unchanged.

Here’s the...

args expression door back right reset

Related Articles