Square Spiral Example

Here is an example of Thun code:

[[[abs]ii <=][[!=][pop !-]or]and][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte

But you wouldn't write it like this. Some layout helps:

[   [[abs] ii <=]
    [
        [!=] [pop !-] or
    ] and
]
[[    !-] [[++]] [[--]] ifte dip]
[[pop !-]  [--]   [++]  ifte    ]
ifte

But even this is not in the spirit of Thun code. Instead we prefer small definitions, functions specified as names (or symbols) followed by expressions:

p0 [abs] ii <=
p1 [!=] [pop !-] or
p  [p0] [p1] and
then [    !-] [[++]] [[--]] ifte dip
else [pop !-]  [--]   [++]  ifte
square_spiral [p] [then] [else] ifte

This might still seem unreadable but I promise with a little familiarity it becomes just as legible as any other notation.

So what does it do?

This function accepts two integers on the stack and increments or decrements one of them such that the new pair of numbers is the next coordinate pair in a square spiral (like the kind used to construct an Ulam Spiral).

Original Form

It's adapted from the original code on StackOverflow:

If all you're trying to do is generate the first N points in the spiral (without the original problem's constraint of masking to an N x M region), the code becomes very simple:

void spiral(const int N)
{
    int x = 0;
    int y = 0;
    for(int i = 0; i < N; ++i)
    {
        cout << x << '\\t' << y << '\\n';
        if(abs(x) <= abs(y) && (x != y || x >= 0))
            x += ((y >= 0) ? 1 : -1);
        else
            y += ((x >= 0) ? -1 : 1);
    }
}

Translation to Thun

We're going to reimplement that if statement in Thun. We'll make a function that expects two integers on the stack representing x and y and computes the next pair of integers.

First Boolean Predicate p0

We need a function that computes abs(x) <= abs(y), we can use ii to apply abs to two values.

joy? 23 -2 [abs] [ii] trace

23 -2 [abs] • ii
         23 • abs -2 abs
         23 • -2 abs
      23 -2 • abs
       23 2 • 
23 2

(The trace facility is only available in the Python implementation.)

Then compare them with <= and that's our first little function:

p0 [abs] ii <=

Second Boolean Predicate p1

There are two "short-circuiting" Boolean combinators and and or that each accept two quoted predicate programs, run the first, and conditionally run the second only if its result is required to compute the final Boolean value. We can translate x != y || x >= 0 as:

p1 [!=] [pop !-] or

Predicate p

We combine the two -sub-predicates with and:

p  [p0] [p1] and

The Increment / Decrement Branches

Turning to the branches of the main if statement:

x += ((y >= 0) ? 1 : -1);

Rewrite as a hybrid (pseudo-code) ifte expression:

[y >= 0] [x += 1] [X -= 1] ifte

Change each C phrase to Thun code:

[0 >=] [[++] dip] [[--] dip] ifte

Factor out the dip from each branch:

[0 >=] [[++]] [[--]] ifte dip

Similar logic applies to the other branch:

y += ((x >= 0) ? -1 : 1);

[x >= 0] [y -= 1] [y += 1] ifte

[pop 0 >=] [--] [++] ifte

So here are the two branches of our ifte:

then [    !-] [[++]] [[--]] ifte dip
else [pop !-] [ -- ] [ ++ ] ifte

Putting the Pieces Together

We can assemble the three functions we just defined in quotes and give them them to the ifte combinator:

square_spiral [p] [then] [else] ifte

Conclusion

So that's an example of Joy code. It's a straightforward translation of the original. It's easy to see that the function is a branch with two quasi-symmetrical paths.