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.

Tags:

Postscript