Using Dyalog APL’s Rank Operator (⍤) for Cell‑Wise Logic: How, When, and What to Watch Out For
Discover how the Rank operator ⍤ lets you apply functions to sub‑arrays (cells) of any rank, replace explicit loops, and when it’s worth the overhead. Includes a worked row‑sum example, dyadic rank demo, and common pitfalls to avoid.
20 Aug 2025, 20:03 UTC

Why Rank (⍤) Is the Right Tool for Cell‑Wise Logic
The Rank operator (⍤) is Dyalog APL’s built‑in way to apply a function to sub‑arrays—called cells—of a specified rank. It replaces the need for explicit loops over rows, columns, or higher‑dimensional planes. Instead of writing ⍤ code that iterates over each row, you can write a single expression that says “apply this function to every rank‑1 cell of the matrix.”
How the Rank Operator Works
F⍤r is a dyadic operator where F is a function (primitive or dfn) and r is the rank specification. The right operand r can be:
- A single number – the rank of the cells to which
Fis applied. - Two numbers – monadic rank for left and right arguments when
Fis dyadic. - Three numbers – monadic rank, left rank, right rank.
⍤¯1 targets the leading axis (rows in a matrix), ⍤0 targets scalars.
Cell Rank, Frame Shape, and Result Shape
The argument is split into cells of rank r. The axes outside those cells form the frame. The result of applying F to each cell is concatenated along the frame axes, producing a result whose shape is:
frame shape ⊕ cell result shape
If the cell results differ in shape, the interpreter nests them into a boxed array. This is a silent way to get a boxed result instead of a rectangle.
Worked Example: Row Sums with +/⍤1
Let’s create a 3×4 matrix:
⎕IO←1 ⍝ 1‑based indexing
mat←3 4⍴⍳12 ⍝ 3 rows, 4 columns
mat
⎕←⎕IO ⍝ reset to 0‑based for clarity
The matrix looks like this:
| 1 | 2 | 3 | 4 |
|---|---|---|---|
| 1 | 2 | 3 | 4 |
| 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 |
Standard reduction +/mat sums along the leading axis (columns) and returns column sums:
+/mat ⍝ → 15 18 21 24
To sum each row, apply +/ to rank‑1 cells (rows) with +/⍤1 mat:
+/⍤1 mat ⍝ → 10 26 42
Here 1 tells the operator to treat each row as a cell, so + is applied to each row vector, producing a 3‑element vector of row sums.
Dyadic Rank: Pairing Scalars with Rows
Dyadic rank lets a function operate on corresponding cells of two arguments. Suppose you have a vector of scalars and want to pair each scalar with a row of mat:
v←10 20 30
v,⍤0 1 mat ⍝ left rank 0 (scalars), right rank 1 (rows)
The frame shape is 3 (three rows). The result is a 3‑element boxed array where each element is a 1×2 vector: the scalar and the row:
{10 1 2 3 4}
{20 5 6 7 8}
{30 9 10 11 12}
If the frame shapes of the two arguments differ, Dyalog signals a length error; it does not broadcast like scalar extension.
Limits and Common Mistakes
- Overhead of Per‑Cell Calls – Using
⍤0with a user‑defined function on a large array can be slower than a whole‑array primitive. Benchmark before adopting rank in hot paths. - Hidden Boxing – When cell results have different shapes, the interpreter nests them into a boxed array. Code that expects a rectangular result may fail unless you explicitly
⍎¨or⍕the boxed array. - No Frame Broadcasting – Unlike scalar extension, dyadic rank does not broadcast frames. A left frame of length 3 against a right frame of length 4 yields a length error.
- Rank Specification Errors – Forgetting that negative ranks count from the end can produce unexpected cell shapes.
⍤¯1applies to rows,⍤0to scalars,⍤2to 2‑D planes. - Non‑Supported Interpreters – The behavior described follows Dyalog APL and the ISO extended standard. APL2, GNU APL, or older systems may lack
⍤or implement it differently. Verify against your runtime’s manual. - Dyadic Rank vs. Axis Operator – Don’t confuse
⍤with the axis operatorF[a](which only applies to certain primitives) or the depth operator⍥(which controls nesting depth).
Practical Engineering Decision
When you need to apply a user‑defined function to each row, column, or higher‑rank slice, ⍤ is concise and expressive. However, for pure numeric reductions (sum, product, max, etc.) on homogeneous data, prefer whole‑array primitives like +/, ⊃+/, ⌿, or ⌿⍤1—they are implemented in C and avoid the per‑cell function call overhead.
Use rank when:
- Each cell requires a different function or a complex dfn.
- You’re working with nested or mixed‑type data where explicit loops are cumbersome.
- Readability and maintainability outweigh a small performance cost.
Use whole‑array primitives when:
- Processing large numeric arrays where speed is critical.
- All cells produce the same shape and you want a flat result.
- You can express the operation with a built‑in reduction or scan.
How to Verify Your Rank Expressions
- Run the Examples – In Dyalog APL (free personal edition) or TryAPL, type the code snippets above and compare results with expected sums.
- Check Frame Compatibility – For dyadic rank, ensure left and right frame shapes match. Use
⍴to inspect shapes. - Profile Performance – Use
⎕TIMEor⎕PROFILEto compare+/⍤1versus a loop or+/on a large matrix. - Inspect Boxed Results – If you suspect hidden boxing, apply
⎕FMTor⍕to the result and verify the shape.
By understanding how rank shapes cells, frames, and results, you can write cleaner, more maintainable APL code while avoiding the pitfalls that often trip newcomers.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.