Bring in the Prolog impl.
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
@@ -0,0 +1,310 @@
|
||||
% With abs as a definition: abs ::= dup 0 < [] [neg] branch
|
||||
|
||||
?- joy(`[abs] ii <=`, [int(A), int(C)], [bool(B)]).
|
||||
|
||||
% Eight solutions:
|
||||
|
||||
B = false,
|
||||
A in 0..sup,
|
||||
A#=<C+ -1,
|
||||
A+1#=_67378,
|
||||
C in 1..sup,
|
||||
C+1#=_67426,
|
||||
_67426 in 1..sup,
|
||||
_67378 in 1..sup ;
|
||||
|
||||
|
||||
B = true,
|
||||
A in 0..sup,
|
||||
A#>=C,
|
||||
A+1#=_67204,
|
||||
C in 0..sup,
|
||||
C+1#=_67252,
|
||||
_67252 in 1..sup,
|
||||
_67204 in 1..sup ;
|
||||
|
||||
|
||||
B = false,
|
||||
A in inf.. -1,
|
||||
_67892+A#=0,
|
||||
A+1#=_67912,
|
||||
_67892 in 1..sup,
|
||||
_67892#=<C+ -1,
|
||||
C in 2..sup,
|
||||
C+1#=_68008,
|
||||
_68008 in 1..sup,
|
||||
_67912 in inf..0 ;
|
||||
|
||||
|
||||
B = true,
|
||||
A in inf.. -1,
|
||||
_67724+A#=0,
|
||||
A+1#=_67744,
|
||||
_67724 in 1..sup,
|
||||
_67724#>=C,
|
||||
C in 0..sup,
|
||||
C+1#=_67834,
|
||||
_67834 in 1..sup,
|
||||
_67744 in inf..0 ;
|
||||
|
||||
|
||||
B = false,
|
||||
A in 0..sup,
|
||||
A#=<_67850+ -1,
|
||||
A+1#=_67870,
|
||||
_67850 in 1..sup,
|
||||
_67850+C#=0,
|
||||
C in inf.. -1,
|
||||
C+1#=_67966,
|
||||
_67966 in inf..0,
|
||||
_67870 in 1..sup ;
|
||||
|
||||
|
||||
B = true,
|
||||
A in 1..sup,
|
||||
A#>=_67762,
|
||||
A+1#=_67780,
|
||||
_67762 in 1..sup,
|
||||
_67762+C#=0,
|
||||
C in inf.. -1,
|
||||
C+1#=_67876,
|
||||
_67876 in inf..0,
|
||||
_67780 in 1..sup ;
|
||||
|
||||
|
||||
B = false,
|
||||
A in inf.. -1,
|
||||
_68746+A#=0,
|
||||
A+1#=_68766,
|
||||
_68746 in 1..sup,
|
||||
_68746#=<_68818+ -1,
|
||||
_68818 in 2..sup,
|
||||
_68818+C#=0,
|
||||
C in inf.. -2,
|
||||
C+1#=_68910,
|
||||
_68910 in inf..0,
|
||||
_68766 in inf..0 ;
|
||||
|
||||
|
||||
B = true,
|
||||
A in inf.. -1,
|
||||
_68258+A#=0,
|
||||
A+1#=_68278,
|
||||
_68258 in 1..sup,
|
||||
_68258#>=_68326,
|
||||
_68326 in 1..sup,
|
||||
_68326+C#=0,
|
||||
C in inf.. -1,
|
||||
C+1#=_68416,
|
||||
_68416 in inf..0,
|
||||
_68278 in inf..0 ;
|
||||
|
||||
|
||||
false.
|
||||
|
||||
|
||||
% If we add a function rule for it using CLP(FD)...:
|
||||
|
||||
func(abs, [int(A)|S], [int(B)|S]) :- B #= abs(A).
|
||||
|
||||
?- joy(`[abs] ii <=`, [int(A), int(C)], [bool(B)]).
|
||||
|
||||
% We get eighteen solutions! Egad.
|
||||
|
||||
B = false,
|
||||
_7784#=abs(A),
|
||||
_7784 in 0..sup,
|
||||
_7784#=<_7836+ -1,
|
||||
_7836 in 1..sup,
|
||||
_7836#=abs(C),
|
||||
C in inf.. -1\/1..sup ;
|
||||
|
||||
|
||||
B = true,
|
||||
_6512#=abs(A),
|
||||
_6512 in 0..sup,
|
||||
_6512#>=_6560,
|
||||
_6560 in 0..sup,
|
||||
_6560#=abs(C) ;
|
||||
|
||||
|
||||
B = false,
|
||||
A in 0..sup,
|
||||
A#=<_8820+ -1,
|
||||
A+1#=_8840,
|
||||
_8820 in 1..sup,
|
||||
_8820#=abs(C),
|
||||
C in inf.. -1\/1..sup,
|
||||
_8840 in 1..sup ;
|
||||
|
||||
|
||||
B = true,
|
||||
A in 0..sup,
|
||||
A#>=_7544,
|
||||
A+1#=_7562,
|
||||
_7544 in 0..sup,
|
||||
_7544#=abs(C),
|
||||
_7562 in 1..sup ;
|
||||
|
||||
|
||||
B = false,
|
||||
A in inf.. -1,
|
||||
_9354+A#=0,
|
||||
A+1#=_9374,
|
||||
_9354 in 1..sup,
|
||||
_9354#=<_9426+ -1,
|
||||
_9426 in 2..sup,
|
||||
_9426#=abs(C),
|
||||
C in inf.. -2\/2..sup,
|
||||
_9374 in inf..0 ;
|
||||
|
||||
|
||||
B = true,
|
||||
A in inf.. -1,
|
||||
_8082+A#=0,
|
||||
A+1#=_8102,
|
||||
_8082 in 1..sup,
|
||||
_8082#>=_8150,
|
||||
_8150 in 0..sup,
|
||||
_8150#=abs(C),
|
||||
_8102 in inf..0 ;
|
||||
|
||||
|
||||
B = false,
|
||||
_7686#=abs(A),
|
||||
_7686 in 0..sup,
|
||||
_7686#=<C+ -1,
|
||||
C in 1..sup,
|
||||
C+1#=_7782,
|
||||
_7782 in 1..sup ;
|
||||
|
||||
|
||||
B = true,
|
||||
_7518#=abs(A),
|
||||
_7518 in 0..sup,
|
||||
_7518#>=C,
|
||||
C in 0..sup,
|
||||
C+1#=_7608,
|
||||
_7608 in 1..sup ;
|
||||
|
||||
|
||||
B = false,
|
||||
A in 0..sup,
|
||||
A#=<C+ -1,
|
||||
A+1#=_8742,
|
||||
C in 1..sup,
|
||||
C+1#=_8790,
|
||||
_8790 in 1..sup,
|
||||
_8742 in 1..sup ;
|
||||
|
||||
|
||||
B = true,
|
||||
A in 0..sup,
|
||||
A#>=C,
|
||||
A+1#=_8568,
|
||||
C in 0..sup,
|
||||
C+1#=_8616,
|
||||
_8616 in 1..sup,
|
||||
_8568 in 1..sup ;
|
||||
|
||||
|
||||
B = false,
|
||||
A in inf.. -1,
|
||||
_9256+A#=0,
|
||||
A+1#=_9276,
|
||||
_9256 in 1..sup,
|
||||
_9256#=<C+ -1,
|
||||
C in 2..sup,
|
||||
C+1#=_9372,
|
||||
_9372 in 1..sup,
|
||||
_9276 in inf..0 ;
|
||||
|
||||
|
||||
B = true,
|
||||
A in inf.. -1,
|
||||
_9088+A#=0,
|
||||
A+1#=_9108,
|
||||
_9088 in 1..sup,
|
||||
_9088#>=C,
|
||||
C in 0..sup,
|
||||
C+1#=_9198,
|
||||
_9198 in 1..sup,
|
||||
_9108 in inf..0 ;
|
||||
|
||||
|
||||
B = false,
|
||||
_8178#=abs(A),
|
||||
_8178 in 0..sup,
|
||||
_8178#=<_8230+ -1,
|
||||
_8230 in 1..sup,
|
||||
_8230+C#=0,
|
||||
C in inf.. -1,
|
||||
C+1#=_8322,
|
||||
_8322 in inf..0 ;
|
||||
|
||||
|
||||
B = true,
|
||||
A in inf.. -1\/1..sup,
|
||||
_9272#=abs(A),
|
||||
_9272 in 1..sup,
|
||||
_9272#>=_9320,
|
||||
_9320 in 1..sup,
|
||||
_9320+C#=0,
|
||||
C in inf.. -1,
|
||||
C+1#=_9410,
|
||||
_9410 in inf..0 ;
|
||||
|
||||
|
||||
B = false,
|
||||
A in 0..sup,
|
||||
A#=<_9214+ -1,
|
||||
A+1#=_9234,
|
||||
_9214 in 1..sup,
|
||||
_9214+C#=0,
|
||||
C in inf.. -1,
|
||||
C+1#=_9330,
|
||||
_9330 in inf..0,
|
||||
_9234 in 1..sup ;
|
||||
|
||||
|
||||
B = true,
|
||||
A in 1..sup,
|
||||
A#>=_9126,
|
||||
A+1#=_9144,
|
||||
_9126 in 1..sup,
|
||||
_9126+C#=0,
|
||||
C in inf.. -1,
|
||||
C+1#=_9240,
|
||||
_9240 in inf..0,
|
||||
_9144 in 1..sup ;
|
||||
|
||||
|
||||
B = false,
|
||||
A in inf.. -1,
|
||||
_10110+A#=0,
|
||||
A+1#=_10130,
|
||||
_10110 in 1..sup,
|
||||
_10110#=<_10182+ -1,
|
||||
_10182 in 2..sup,
|
||||
_10182+C#=0,
|
||||
C in inf.. -2,
|
||||
C+1#=_10274,
|
||||
_10274 in inf..0,
|
||||
_10130 in inf..0 ;
|
||||
|
||||
|
||||
B = true,
|
||||
A in inf.. -1,
|
||||
_9622+A#=0,
|
||||
A+1#=_9642,
|
||||
_9622 in 1..sup,
|
||||
_9622#>=_9690,
|
||||
_9690 in 1..sup,
|
||||
_9690+C#=0,
|
||||
C in inf.. -1,
|
||||
C+1#=_9780,
|
||||
_9780 in inf..0,
|
||||
_9642 in inf..0 ;
|
||||
|
||||
|
||||
false.
|
||||
@@ -0,0 +1,4 @@
|
||||
Talk about minimal basis, Kirby (sp?) has found a basis involving a
|
||||
combinator he calls 'cake'...
|
||||
|
||||
Branch, Loop, Sequence, Parallel.
|
||||
@@ -0,0 +1,225 @@
|
||||
___ _ ___ _
|
||||
| __|_ ____ _ _ __ _ __| |___ / __|___ __| |___
|
||||
| _|\ \ / _` | ' \| '_ \ / -_) | (__/ _ \/ _` / -_)
|
||||
|___/_\_\__,_|_|_|_| .__/_\___| \___\___/\__,_\___|
|
||||
|_|
|
||||
# On the Square Spiral Example Code
|
||||
|
||||
Here is the example of Joy code from the `README` file:
|
||||
|
||||
[[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
|
||||
|
||||
It might seem unreadable but with a little familiarity it becomes just as
|
||||
legible as any other notation. Some layout helps:
|
||||
|
||||
[ [[abs] ii <=]
|
||||
[
|
||||
[<>] [pop !-] ||
|
||||
] &&
|
||||
]
|
||||
[[ !-] [[++]] [[--]] ifte dip]
|
||||
[[pop !-] [--] [++] ifte ]
|
||||
ifte
|
||||
|
||||
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](https://stackoverflow.com/questions/398299/looping-in-a-spiral/31864777#31864777):
|
||||
|
||||
> 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);
|
||||
}
|
||||
}
|
||||
|
||||
> The trick is that you can compare x and y to determine what side of the
|
||||
> square you're on, and that tells you what direction to move in.
|
||||
|
||||
|
||||
## Translation to Joy
|
||||
|
||||
I'm going to make a function that take two ints (`x` and `y`) and
|
||||
generates the next pair, we'll turn it into a generator later using the
|
||||
`x` combinator.
|
||||
|
||||
### First Boolean Predicate
|
||||
|
||||
We need a function that computes `abs(x) <= abs(y)`, we can use `ii` to
|
||||
apply `abs` in parallel (eventually) to both values and then compare them
|
||||
with `<=`:
|
||||
|
||||
[abs] ii <=
|
||||
|
||||
I've defined two short-circuiting Boolean combinators `&&` and `||` that
|
||||
each accept two quoted predicate programs, run the first, and
|
||||
conditionally run the second only if required (to compute the final
|
||||
Boolean value). They run their predicate arguments `nullary`. Given
|
||||
those, we can define `x != y || x >= 0` as:
|
||||
|
||||
[<>] [pop 0 >=] ||
|
||||
|
||||
And `(abs(x) <= abs(y) && (x != y || x >= 0))` as:
|
||||
|
||||
[[abs] ii <=] [[<>] [pop 0 >=] ||] &&
|
||||
|
||||
It's a little rough, but, as I say, with a little familiarity it becomes
|
||||
legible.
|
||||
|
||||
### 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 Joy 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
|
||||
|
||||
|
||||
## Putting the Pieces Together
|
||||
|
||||
We can assemble the three functions we just defined in quotes and give
|
||||
them them to the `ifte` combinator. With some arrangement to show off
|
||||
the symmetry of the two branches, we have:
|
||||
|
||||
[[[abs] ii <=] [[<>] [pop !-] ||] &&]
|
||||
[[ !-] [[++]] [[--]] ifte dip]
|
||||
[[pop !-] [--] [++] ifte ]
|
||||
ifte
|
||||
|
||||
As I was writing this up I realized that, since the `&&` combinator
|
||||
doesn't consume the stack (below its quoted args), I can unquote the
|
||||
predicate, swap the branches, and use the `branch` combinator instead of
|
||||
`ifte`:
|
||||
|
||||
[[abs] ii <=] [[<>] [pop !-] ||] &&
|
||||
[[pop !-] [--] [++] ifte ]
|
||||
[[ !-] [[++]] [[--]] ifte dip]
|
||||
branch
|
||||
|
||||
|
||||
## Turning it into a Generator with `x`
|
||||
|
||||
It can be used with the x combinator to make a kind of generator for
|
||||
spiral square coordinates.
|
||||
|
||||
|
||||
We can use `codireco` to make a generator
|
||||
|
||||
codireco ::= cons dip rest cons
|
||||
|
||||
It will look like this:
|
||||
|
||||
[value [F] codireco]
|
||||
|
||||
Here's a trace of how it works:
|
||||
|
||||
[0 [dup ++] codireco] . x
|
||||
[0 [dup ++] codireco] . 0 [dup ++] codireco
|
||||
[0 [dup ++] codireco] 0 . [dup ++] codireco
|
||||
[0 [dup ++] codireco] 0 [dup ++] . codireco
|
||||
[0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
|
||||
[0 [dup ++] codireco] [0 dup ++] . dip rest cons
|
||||
. 0 dup ++ [0 [dup ++] codireco] rest cons
|
||||
0 . dup ++ [0 [dup ++] codireco] rest cons
|
||||
0 0 . ++ [0 [dup ++] codireco] rest cons
|
||||
0 1 . [0 [dup ++] codireco] rest cons
|
||||
0 1 [0 [dup ++] codireco] . rest cons
|
||||
0 1 [[dup ++] codireco] . cons
|
||||
0 [1 [dup ++] codireco] .
|
||||
|
||||
But first we have to change the `spiral_next` function to work on a
|
||||
quoted pair of integers, and leave a copy of the pair on the stack.
|
||||
From:
|
||||
|
||||
y x spiral_next
|
||||
---------------------
|
||||
y' x'
|
||||
|
||||
to:
|
||||
|
||||
[x y] [spiral_next] infra
|
||||
-------------------------------
|
||||
[x' y']
|
||||
|
||||
So our generator is:
|
||||
|
||||
[[x y] [dup [spiral_next] infra] codireco]
|
||||
|
||||
Or rather:
|
||||
|
||||
[[0 0] [dup [spiral_next] infra] codireco]
|
||||
|
||||
There is a function `make_generator` that will build the generator for us
|
||||
out of the value and stepper function:
|
||||
|
||||
[0 0] [dup [spiral_next] infra] make_generator
|
||||
----------------------------------------------------
|
||||
[[0 0] [dup [spiral_next] infra] codireco]
|
||||
|
||||
Here it is in action:
|
||||
|
||||
?- joy(`[[0 0] [dup [spiral_next] infra] codireco] x x x x pop`, [], _So),
|
||||
| joy_terms_to_string(_So, S).
|
||||
|
||||
_So = [list([int(-1), int(0)]), list([int(-1), int(1)]), list([int(0), int(1)]), list([int(0), int(0)])],
|
||||
|
||||
S = "[-1 0] [-1 1] [0 1] [0 0]" .
|
||||
|
||||
Four `x` combinators, four pairs of coordinates.
|
||||
|
||||
|
||||
## Conclusion
|
||||
|
||||
So that's an example of Joy code. It's a straightforward translation of
|
||||
the original. It's a little long for a single definition, you might
|
||||
break it up like so:
|
||||
|
||||
_spn_P ::= [[abs] ii <=] [[<>] [pop !-] ||] &&
|
||||
|
||||
_spn_T ::= [ !-] [[++]] [[--]] ifte dip
|
||||
_spn_E ::= [pop !-] [--] [++] ifte
|
||||
|
||||
spiral_next ::= _spn_P [_spn_E] [_spn_T] branch
|
||||
|
||||
This way it's easy to see that the function is a branch with two
|
||||
quasi-symmetrical paths.
|
||||
|
||||
We then used this function to make a simple generator of coordinate
|
||||
pairs, where the next pair in the series can be generated at any time by
|
||||
using the `x` combinator on the generator (which is just a quoted
|
||||
expression containing a copy of the current pair and the "stepper
|
||||
function" to generate the next pair from that.)
|
||||
@@ -0,0 +1,61 @@
|
||||
# list-structured memory
|
||||
|
||||
[In SICP, section 5.3, "Storage Allocation and Garbage Collection"](https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-33.html#%_sec_5.3):
|
||||
|
||||
> In order to simplify the discussion, we will assume that our register
|
||||
machines can be equipped with a list-structured memory, in which the
|
||||
basic operations for manipulating list-structured data are primitive.
|
||||
|
||||
So they bunt to an abstraction and then implement that abstraction as a
|
||||
separate problem. Makes sense. I see no reason not to adopt the design
|
||||
described here.
|
||||
|
||||
------------------
|
||||
|
||||
# Machine Ints vs BigNums
|
||||
|
||||
Already there is a problem in the semantics. SWI Prolog integers can be
|
||||
larger than machine words, which in the RISC CPU are thirty-two bits.
|
||||
(GNU Prolog uses machine words for its integers). THe main options are:
|
||||
|
||||
1. Implements "BigNums" for Wirth RISC.
|
||||
|
||||
2. Adjust the semantics of Thun to reflect the modular arithmetic of
|
||||
machine words and native machine integer math operations.
|
||||
|
||||
3. ... something else.
|
||||
|
||||
------------------
|
||||
|
||||
# specialized versions of `branch` and `ifte`
|
||||
|
||||
THere's another semantic wrinkle with branches and Boolean values.
|
||||
Namely, the CPU provides the condition and the offset in one instruction
|
||||
whereas Joy has them separated. I have been thinking about introducing
|
||||
specialized versions of `branch` as primitives:
|
||||
|
||||
=branch
|
||||
>branch
|
||||
<branch
|
||||
<=branch
|
||||
>=branch
|
||||
<>branch
|
||||
|
||||
Or maybe:
|
||||
|
||||
=?
|
||||
>?
|
||||
<?
|
||||
<=?
|
||||
>=?
|
||||
<>?
|
||||
|
||||
Anyway, it would be pretty easy to detect simple cases of the split
|
||||
pattern and convert them automatically, but the programmer could use them
|
||||
directly whenever it made sense.
|
||||
|
||||
> [F] [T] branch ==> [F] [T] >branch
|
||||
|
||||
Probably specialized versions of `ifte` would be useful as well.
|
||||
|
||||
------------------
|
||||
Reference in New Issue
Block a user