Reverse and Rotate

The symbol ⌽ indicates two different array transformations: with no left argument, it reverses the major cells of the array, but with a left argument, it rotates or cycles them around. These two possibilities, first put together in very early versions of APL, can't be considered restrictions or different views of some unifying function, but there are connections between them. Each returns an array with the same shape and all the same elements as 𝕩, possibly in a different arrangement. And elements that start out next to each other in 𝕩 generally stay next to each otherβ€”always, if we consider an element on one edge to be next to the one opposite to it. One might think of them as isometries preserving a discrete subgroup of the torus, if one were inclined to think such things. On major cells, the two functions decompose the dihedral group okay I'll stop.

If there's no reason the data should be seen as cyclic or periodic, it's best to avoid Rotate: shift functions are probably more appropriate.

Reverse

Reverse doesn't make things complicated. It puts the elements of a list the other way around, or more generally the major cells of an array.

↗️
    ⌽ "abcdefg"
"gfedcba"

    ⌽ >"ab"β€Ώ"cd"β€Ώ"ef"
β”Œβ”€    
β•΅"ef  
  cd  
  ab" 
     β”˜

    ⌽ 'c'
Error: ⌽: Argument cannot be a unit

You can't reverse an atom or rank-0 array because it has no axes to reverse along, or it could be said no ordering to reverse.

To reverse along an axis other than the first, use Cells (˘) or Rank (βŽ‰).

↗️
    ⌽˘ >"ab"β€Ώ"cd"β€Ώ"ef"
β”Œβ”€    
β•΅"ba  
  dc  
  fe" 
     β”˜

Reverse is useful for folding left to right instead of right to left (here we use Pair to show structure).

↗️
    β‹ˆ Β΄   "abcd"  # Right to left
⟨ 'a' ⟨ 'b' "cd" ⟩ ⟩

    β‹ˆΛœΒ΄ ⌽ "abcd"  # Left to right
⟨ ⟨ "ab" 'c' ⟩ 'd' ⟩

Reverse is its own inverse ⌽⁼. So with Under, π”½βŒΎβŒ½ reverses the argument, applies 𝔽, and reverses again. It's a particularly useful pattern with Scan, as it allows scanning from the end rather than the beginning of the array. For example, ∨` on a list of booleans changes all bits after the first 1 to 1, but ∨`⌾⌽ does this to all bits before the last 1.

↗️
    ∨`   0β€Ώ0β€Ώ1β€Ώ0β€Ώ0β€Ώ1β€Ώ0
⟨ 0 0 1 1 1 1 1 ⟩

    ∨`⌾⌽ 0β€Ώ0β€Ώ1β€Ώ0β€Ώ0β€Ώ1β€Ώ0
⟨ 1 1 1 1 1 1 0 ⟩

Rotate

Rotate moves elements in a list around cyclically. It can also rotate any number of axes of the argument array by different amounts at once. That's discussed in the next section; for now we'll stick to a single number for 𝕨. It has to be an integer, and 𝕩 has to be an array with at least one axis.

↗️
    2 ⌽ "rotate"
"tatero"

    2 (⊒ β‹ˆ ⌽) 5β€Ώ2β₯Š"rotateCELL"
β”Œβ”€               
Β· β”Œβ”€     β”Œβ”€      
  β•΅"ro   β•΅"te    
    ta     CE    
    te     LL    
    CE     ro    
    LL"    ta"   
       β”˜      β”˜  
                β”˜

    2 ⌽ 'c'  # No axes to rotate
Error: ⌽: 𝕩 must have rank at least 1 for atom 𝕨

Elements are always rotated to the left, so that entry i of the result is entry 𝕨+i of the argumentβ€”or rather, entry (≠𝕩)|𝕨+i to enable elements to cycle around. This can be seen directly by using the range ↕n as an argument: then the value of 𝕩 at index i is just i.

↗️
    2 ⌽ ↕6
⟨ 2 3 4 5 0 1 ⟩

The rotation (≠𝕩)βŒ½π•© moves each element the entire length of 𝕩, which just places it back where it started. In fact, adding ≠𝕩 to the rotation amount never changes the behavior or the rotation. In terms of indices, this is because (≠𝕩)|(≠𝕩)+a is a.

To rotate the other way, use a negative left argument (so -⊸⌽ is a simple way to write "reverse rotate"). This will always be the same as some leftwards rotation, since (-r)βŒ½π•© is ((≠𝕩)-r)βŒ½π•©, but could be more convenient.

↗️
    ¯2 ⌽ "rotate"
"terota"

Multiple axes

The easiest way to rotate along a later array axis is usually to use the Cells (˘) or Rank (βŽ‰) modifier.

↗️
    ⊒ tab ← 3β€Ώ4β₯Š"abcdABCD0123"
β”Œβ”€      
β•΅"abcd  
  ABCD  
  0123" 
       β”˜

    1 ⌽˘ tab  # Rotate the second axis
β”Œβ”€      
β•΅"bcda  
  BCDA  
  1230" 
       β”˜

Rotate also allows 𝕨 to be a list (or unit array) of integers, in which case they're matched with leading axes of 𝕩. This means the length of 𝕨 can't be larger than the rank of 𝕩, or there wouldn't be enough axes to match. This rule that 𝕩 has to have rank one or more when 𝕨 is an atom is a special case, because then 𝕨 is treated as the one-element list β₯Šπ•¨.

↗️
    3β€Ώ4β€Ώ2 ⌽ "just a list"
Error: π•¨βŒ½π•©: Length of compound 𝕨 must be at most rank of 𝕩

The expression below rotates the first (vertical) axis of tab by one element, and second by two. So the line of capital letters goes from being one away from the top, up to the top, and the column with '2' goes from horizontal index 2 to index 0.

↗️
    1β€Ώ2 ⌽ tab
β”Œβ”€      
β•΅"CDAB  
  2301  
  cdab" 
       β”˜

The vertical and horizontal rotations are independent, and could also be done with two ⌽s and a ˘. The multi-axis form is more convenient, and can potentially be evaluated faster than multiple separate rotations in the cases where it shows up.

↗️
    1 ⌽ 2 ⌽˘ tab
β”Œβ”€      
β•΅"CDAB  
  2301  
  cdab" 
       β”˜