Welcome to the Parallax Discussion Forums, sign-up to participate.

# Three new keywords for Spin 1 & 2?

Posts: 22,838
I've been working with permutations recently and came across Heap's algorithm for generating all n! permutations of a list of length n. In Spin, the program looks like this:
```CON

_clkmode      = xtal1 + pll16x
_xinfreq      = 5_000_000

SIZE          = 4

VAR

byte array[SIZE + 1]

OBJ

sio:  "Parallax Serial Terminal"

PUB start | i

sio.start(9600)
bytemove(@array, string("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), SIZE)
generate(@array, SIZE)

if (len == 1)
else
repeat i from 0 to len - 1
if (len & 1)
else

PRI factorial(n)

result := 1
repeat n
result *= (n--)

PRI swap(addr, i, j) | t

sio.char(13)
```

and produces this output:
```ABCD
BACD
CABD
ACBD
DBCA
BDCA
CDBA
DCBA
BCDA
CBDA
DACB
CDAB
DCAB
ACDB
DABC
BDAC
DBAC
ABDC
```

What I really want is a routine that simply returns the next permutation in Heap's sequence, not all of them. Of course, there's a lot of state information in that algo that needs to be preserved between calls. The easiest way to do this in Spin is to put generate in its own cog and use flags to stimulate the next value, like this:
```CON

_clkmode      = xtal1 + pll16x
_xinfreq      = 5_000_000

SIZE          = 4

VAR

byte array[SIZE + 1], need, ready
long stack[SIZE * 10]

OBJ

sio:  "Parallax Serial Terminal"

PUB start | i

sio.start(9600)
bytemove(@array, string("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), SIZE)
cognew(generate(@array, SIZE), @stack)
repeat factorial(SIZE)
need~~
sio.str(@array)
sio.char(13)

repeat
if (len == 1)
repeat until need
need~
else
repeat i from 0 to len - 1
if (len & 1)
else

PRI factorial(n)

result := 1
repeat n
result *= (n--)

PRI swap(addr, i, j) | t

sio.char(13)
```

It produces the same output as before, but it needs a separate cog to do so.

What is needed here are three new keywords, begin, pause, and resume, that can be used to stop a method, then resume it from where it leaves off, without needing to run it in a separate cog. Of course, the method would still need its own stack. It would be used like this:
```CON

_clkmode      = xtal1 + pll16x
_xinfreq      = 5_000_000

SIZE          = 4

VAR

byte array[SIZE + 1]
long stack[SIZE * 10]

OBJ

sio:  "Parallax Serial Terminal"

PUB start | i

sio.start(9600)
bytemove(@array, string("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), SIZE)
begin(generate(@array, SIZE), @stack)
repeat factorial(SIZE)
sio.str(@array)
sio.char(13)
resume(generate)

repeat
if (len == 1)
pause
else
repeat i from 0 to len - 1
if (len & 1)
else

PRI factorial(n)

result := 1
repeat n
result *= (n--)

PRI swap(addr, i, j) | t

sio.char(13)
```

begin and resume execute the generate method in the same cog until generate hits a pause, which returns to the calling program. The pause keyword could also return a value, accessible by the resume call.

-Phil