How do you keep the `roll` operator straight?
I had difficulty with roll for a very long time. I remember it now using these ways, which are all equivalent:
the rhyme (-ish)
n j roll
positive j, to roll away
7 8 9 3 1 roll % 9 7 8
negative, to get it back (or "negateeve, to then retrieve")
% 9 7 8 3 -1 roll % 7 8 9
stack (of things)
Perhaps a better way to think of it is a physical stack (of books, say) so the top of stack is literally "on top".
Then a positive roll goes up:
for j number of times pick up n books put the top one on the bottom (shifting the substack "up") put them back down
And a negative roll goes down:
for j number of times pick up n books put the bottom one on top (shifting the substack "down") put them back down
sideways
But I usually picture the stack sideways, the way the objects would look in a file as a sequence of literals. So I think of the positive roll as stashing the top j things behind the nth thing; and the negative roll as snagging j things starting with the nth thing. Give and Take.
Away.
n j roll
__ j > 0 __ move top j elements to the bottom of n
n TOS
-------------|
| j |
| -----|
| | |
V V |
a b c d e f g h
^ | |
| |-------|
^ |
-<-<-<-<-<-
move
And back.
__ j < 0 __ move j elements from the bottom of n to the top
n TOS
-------------|
| j |
|----- |
| | |
V V |
a b c d e f g h
| | ^
|-------| |
| ^
->->->->->-
move
lint-roller
Still another way is to picture it sideways, and laying a sticky wheel on top (a lint-roller, maybe)
(a) (b) (c) (d) (e) 5 3 roll _______ / \ | 3 | | / | \ | \_______/ (a) (b) (c) (d) (e)
Then a positive roll goes counterclockwise just like arc and rotate.
_______ (e) / / \ | 3 --| (d) | \ | \_______/ (c) (a) (b) (e)__(d)__(c) /\ | /\ | 3 | | | \_______/ (a) (b) (c)_______ /\ \ (d) |-- 3 | |/ | \_______/ (e) (a) (b) _______ / \ | 3 | | / | \ | \_______/ (c) (d) (e) (a) (b)
And a negative roll goes clockwise like arcn and a negative rotation.
_______ / \ | 3 | | / | \ | \_______/ (a) (b) (c) (d) (e) (a)_______ /\ \ (b) |-- 3 | |/ | \_______/ (c) (d) (e) (c)__(b)__(a) /\ | /\ | 3 | | | \_______/ (d) (e) _______ (c) / / \ | 3 --| (b) | \ | \_______/ (a) (d) (e) _______ / \ | 3 | | / | \ | \_______/ (d) (e) (a) (b) (c)
eliminate the negative
It shouldn't be difficult to see that negative rolls are entirely unnecessary because if j<0, it can be replaced by n-j. eg.
3 -1 roll % roll bottom 1 element from 3 to the top
3 2 roll % roll top 2 elements behind the 3rd
are the same.
16 -4 roll % roll bottom 4 elements from 16 to the top
16 12 roll % roll top 12 elements behind the 16th
are the same.
This leads to the final, ultimate simplified view (though each of the above will work, too).
Roll is just a big Swap
You're really just exchanging the top j elements with the n-j elements below that.
Say you have this mess on the stack (where $TOS$ marks the top of the stack), and want to order it properly:
g h i j k l m n o p q r s t u v w x y z a b c d e f $TOS$
Count up (down) for n and j.
g h i j k l m n o p q r s t u v w x y z a b c d e f
26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
| | j = 6 . . . .
| n = 26 . . . . . . . . . . . . . . . . . . . . . . .
> 26 6 roll pstack
a b c d e f g h i j k l m n o p q r s t u v w x y z
A negative value for j simply positions that dividing line relative to the deepest element from among the n elements (it counts from below).
t u v w x y z a b c d e f g h i j k l m n o p q r s
26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
. . . . j = -7 | |
. . . . . . . . . . . . . . . . . . . . . . . n = 26 |
> 26 -7 roll pstack
a b c d e f g h i j k l m n o p q r s t u v w x y z
Here is a convenience function that gives an interface to roll that's more closely analogous to the big swap view.
% r0..rN s0..sM N M swap s0..sM r0..rN
% a gentler interface to the power of roll
/swap {
exch 1 index add exch
roll
} def
0 1 2 3 /a /b /c 4 3 swap pstack
Output:
GPL Ghostscript 8.62 (2008-02-29)
Copyright (C) 2008 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
3
2
1
0
/c
/b
/a
GS<7>GS<7>
Simple saying: if you make some round object roll, its distance from you will probably be greater after than before, unless you use something else than you hand (e.g.: a magical wand, ...) to make the object roll.
5 1 roll
means that the 1
object on the top of the stack will afterwards be at a greater distance from the top of the stack.
10 11 12 13 14 15 16 17 18 19 20 5 1 roll
is the same than
10 11 12 13 14 15 20 16 17 18 19
You see 20 has gone deeper, and last five element changed position.
5
in 5 1 roll
means that only the five first objects from the stack may all change position.
-1
and 4
are the same modulo 5
, hence it is easy to remember that negative numbers have to be modified to be positive before applying this solution.