⎕IO←1, the Dyalog convention this tutorial uses); output spacing can differ slightly
from Dyalog. Voice input works in Chrome, Edge and Safari, over https or localhost.
Claude mode (natural language → APL) needs your own Anthropic API key — press ⚙.
APL: Programming as Notation
A different way to think about computers
Most introductions to programming start the same way: you learn to write instructions, one after another, that tell the computer what to do step by step. Loop over this list. Check this condition. Add this number to that running total. Programming, in this view, is bureaucracy — careful, explicit paperwork for a very fast but very literal clerk.
APL starts somewhere else entirely. It was invented in the early 1960s by Kenneth Iverson, a mathematician who wasn't trying to build a programming language at all. He was trying to fix mathematical notation — to make it consistent and precise enough that you could actually execute it. The result, which he simply called "A Programming Language" (hence APL), treats a program less like a recipe and more like an equation.
Two ideas make APL feel unlike anything else:
First, it uses its own symbols. Where other languages spell things out (sum, reverse, sort), APL has a single character for each fundamental operation: +/ sums, ⌽ reverses, ⍋ sorts. This looks intimidating for about an hour. Then something clicks: you stop reading programs word by word and start reading them the way you read 3 + 4 — at a glance. Nobody thinks + is scary, and APL is just more of that.
Second, it works on whole collections of data at once. In most languages, to double every number in a list, you write a loop: "for each number, multiply it by two, put the result somewhere." In APL you write:
2 × 1 2 3 4 5
2 4 6 8 10
That's it. No loop, no counter, no "for each." You said what you meant — double these numbers — and the language handled the rest. This is called array programming, and it's APL's big idea. It turns out that an enormous amount of what programs do is really just "do this to everything in the collection," and APL makes that the default instead of something you have to construct by hand.
By the end of this tutorial you'll be able to read — genuinely read — a complete implementation of Conway's Game of Life written in a single line of APL. That sounds like a party trick, and it partly is. But getting there will teach you a way of thinking about computation that shows up everywhere in modern computing, from spreadsheets to the software behind AI.
Getting set up
You don't need to install anything. Go to tryapl.org — it's a free APL environment that runs in your browser, maintained by Dyalog, the company behind the main modern APL implementation.
How do you type these symbols?
Fair question — ⍴ and ⌽ are not on your keyboard. In APL's early days this was solved with hardware: dedicated keyboards and even special typewriter balls with the symbols engraved on them. Today the solution is much simpler: a prefix key. You type one ordinary key to say "the next keystroke is an APL symbol," then an ordinary key for the symbol itself. The standard prefix is the backtick ` (upper-left corner of most keyboards).
The mappings are mnemonic wherever possible, which makes them easy to absorb:
| You type | You get | Mnemonic |
|---|---|---|
`i |
⍳ |
iota |
`r |
⍴ |
rho |
`w |
⍵ |
omega, and it looks like a w |
`- |
× |
on the same key as minus |
`= |
÷ |
opposite of, er, nothing — it's just next door |
TryAPL supports this backtick scheme directly, and it also has a clickable language bar across the top with every symbol — hover over any of them to see its name and its keyboard shortcut. Use the language bar freely at first. The tutorial ahead needs only about twenty symbols, and the ones you use often will be in your fingers within a session or two.
(If you later install APL on your own machine, Dyalog sets up the same kind of input system there, and there are plugins for popular code editors that do likewise. The typing problem is thoroughly solved; don't let it be the thing that puts you off.)
In the examples below, the indented line is what you type, and the line under it is what APL prints back.
First steps: the calculator that grew
APL is, at minimum, a calculator:
3 + 4
7
10 - 3
7
6 × 7
42
10 ÷ 4
2.5
Notice it uses real multiplication and division signs, × and ÷, not the * and / most languages settle for. Iverson designed APL for humans first.
Now the first surprise. Put several numbers next to each other, separated by spaces, and you have a vector — a list of numbers that acts like a single value:
1 2 3 + 10 20 30
11 22 33
Each number on the left paired up with the corresponding number on the right. And you can mix a single number with a vector:
5 + 1 2 3 4
6 7 8 9
The 5 was applied to everything. Every arithmetic operation in APL works this way, on data of any size. This one fact is the seed the whole language grows from.
One rule you must know: right to left
APL evaluates expressions from right to left, with no operator precedence. There's no "multiplication before addition." So:
3 × 2 + 1
9
APL reads this as 3 × (2 + 1), not (3 × 2) + 1. It computes 2 + 1 first (rightmost), then multiplies by 3. This feels wrong for a day and then becomes a relief: with dozens of symbols, memorizing a precedence table would be hopeless. Instead there's one rule, and parentheses when you want a different order:
(3 × 2) + 1
7
One more small thing: APL writes negative numbers with a raised minus, ¯3, to distinguish "the number negative three" from "subtract three." You'll see ¯1 later; it just means −1.
Naming things
The left arrow assigns a name to a value:
prices ← 12 8 30 5 15
prices × 2
24 16 60 10 30
The vocabulary starts to build
Let's meet a few symbols. Each one does something small and clean.
⍳ (iota) — count up to. Give it a number, it gives you the first n counting numbers:
⍳ 10
1 2 3 4 5 6 7 8 9 10
≢ (tally) — how many. Counts the items in a vector:
≢ 4 8 15 16 23 42
6
⌽ — reverse:
⌽ ⍳ 5
5 4 3 2 1
⍴ (rho) — reshape. This one reveals that APL isn't limited to flat lists. Give ⍴ dimensions on the left and data on the right, and it builds a table — a matrix:
3 4 ⍴ ⍳ 12
1 2 3 4
5 6 7 8
9 10 11 12
"Reshape the numbers 1 through 12 into 3 rows of 4." Vectors, matrices, and higher-dimensional blocks are all just arrays, and everything you've learned so far works on all of them. 2 × that matrix and every one of the twelve numbers doubles.
A dirty secret that's actually a design principle
You may have noticed ⌽ reversed a vector, but I said symbols do one thing each. Here's the refinement: most APL symbols do two related things, depending on whether you give them one argument (on the right) or two (one on each side).
⌽ with one argument reverses. With a number on the left, it rotates:
1 ⌽ 1 2 3 4 5
2 3 4 5 1
¯1 ⌽ 1 2 3 4 5
5 1 2 3 4
Rotate by 1 shifts everything left (the front wraps to the back); rotate by ¯1 shifts right. Hold onto this — rotation is the key trick in the Game of Life.
Similarly, ⍴ with one argument asks the shape instead of setting it:
⍴ 3 4 ⍴ ⍳ 12
3 4
These pairings aren't arbitrary; the two meanings always rhyme. Reverse is rotate's sibling. Shape is reshape's question form. Learning APL is largely learning these rhymes.
Operators: functions that build functions
Here's where APL goes from "neat calculator" to genuinely powerful. Some symbols don't operate on data — they operate on other functions, producing new functions. APL calls these operators.
The most important is / — reduce. It takes a function and folds it between every element of an array:
+/ 1 2 3 4 5
15
+/ means "put a + between everything": 1+2+3+4+5. But / isn't tied to + — it works with any function:
×/ 1 2 3 4 5
120
⌈/ 3 1 4 1 5 9 2 6
9
×/ multiplies everything together. ⌈ is maximum (of two numbers), so ⌈/ is maximum of the whole list. You didn't learn three functions there — you learned one operator, and it multiplied your vocabulary.
Now you can write things that would be several lines in most languages. The average of a list is "the sum divided by the count":
nums ← 31 4 15 92 65
(+/ nums) ÷ ≢ nums
41.4
Read it right to left: tally the numbers, and separately sum them (the parentheses group the sum), then divide. That expression is the definition of an average. Nothing is lost in translation between the idea and the code.
There's a cousin, \ — scan — which is reduce but keeping all the intermediate results:
+\ 1 2 3 4 5
1 3 6 10 15
Running totals, in two characters.
Asking questions of data
Comparisons in APL return numbers: 1 for true, 0 for false. And like everything else, they work on whole arrays:
temps ← 68 75 82 79 65 88 91
temps > 80
0 0 1 0 0 1 1
That vector of 1s and 0s is a boolean mask, and it's more useful than it looks, because 1s and 0s are numbers you can do arithmetic on. How many days were over 80?
+/ temps > 80
3
Sum the mask: counting is just adding up the "yes"es. Want the actual values? / between two arrays means compress — keep the items where the mask is 1:
(temps > 80) / temps
82 88 91
"Filter" in most languages is a built-in feature you look up. Here it fell out of arithmetic.
One more classic. ⍋ (grade) doesn't sort a list — it tells you the order you'd need to sort it, as positions. Indexing with square brackets then does the rearranging:
⍋ temps
5 1 2 4 3 6 7
temps[⍋ temps]
65 68 75 79 82 88 91
Splitting "figure out the order" from "apply the order" sounds fussy until you want to sort one list by another — names by ages, say — at which point it's exactly right: names[⍋ ages].
The finale: Conway's Game of Life in one line
Time to cash in everything you've learned.
The Game of Life is a famous simulation played on a grid of cells, each either alive (1) or dead (0). The grid evolves in generations by two rules based on each cell's eight neighbors:
- A live cell with 2 or 3 live neighbors survives; otherwise it dies.
- A dead cell with exactly 3 live neighbors becomes alive.
In most languages this is a page of code: nested loops over rows and columns, fiddly bookkeeping at the edges, off-by-one bugs. Here it is in APL — a celebrated one-liner from the Dyalog community:
life ← {↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}
Don't panic. You can read most of this already, and we'll take it slowly, right to left. Two bits of new notation first: the braces {} define a function, and inside them ⍵ (omega) is the name for whatever the function is given — the grid.
Step 1: ⊂⍵ — package the grid. ⊂ wraps the whole matrix up as a single item, so the next operations treat it as one object to be copied and shifted, rather than reaching inside it.
Step 2: ¯1 0 1 ∘.⌽ ⊂⍵ — three shifted copies. You know ⌽ with a left argument rotates. ∘. is a new operator, outer product: "apply this function between every item on the left and every item on the right." Here the left side is ¯1 0 1 and the right side is our one packaged grid, so we get three copies of the grid: rotated one column left, unmoved, and one column right.
Step 3: ¯1 0 1 ∘.⊖ ... — nine shifted copies. ⊖ is ⌽'s vertical twin: it rotates rows instead of columns. Taking the outer product of ¯1 0 1 against our three copies shifts each of them up, not-at-all, and down. Result: a 3-by-3 collection of grids, each shifted one step in one of the nine directions (including "not shifted").
Why do this? Because of a lovely inversion: instead of each cell looking around at its neighbors, we shift the whole world so that every neighbor comes to visit. In the copy shifted down-and-right, the value sitting at your position is your upper-left neighbor's.
Step 4: +/, — count the neighbors. , flattens the 3×3 collection into a list of nine grids, and +/ — our old friend — adds them all up, grid on grid. The result is a single matrix where each cell holds a count: itself plus its eight neighbors.
Step 5: 3 4 = — apply the rules. Comparing the count matrix against 3 4 gives two boolean masks: "cells whose neighborhood sums to exactly 3" and "cells whose neighborhood sums to exactly 4." Here's the cleverness — remember the count includes the cell itself:
- A sum of 3 means: either a dead cell with 3 live neighbors (birth!) or a live cell with 2 (survival!). Either way, that cell is alive next generation, no matter what it is now.
- A sum of 4 means alive next generation only if the cell is currently alive (a live cell with 3 neighbors). If it's dead with 4 neighbors — dead it stays.
Step 6: 1 ⍵ ∨.∧ — combine. In words: "(everyone, where the sum is 3) OR (currently-alive cells, where the sum is 4)." ∧ is AND, ∨ is OR, and the . stitches them into a combined operation that pairs 1 with the sum-is-3 mask and the original grid ⍵ with the sum-is-4 mask, then ORs the results. That's rules 1 and 2, in six characters.
Step 7: ↑ — unpack. The result is still wrapped up from step 1; ↑ unpacks it back into an ordinary grid.
Try it on TryAPL with a "glider," a small pattern famous for crawling diagonally across the grid:
grid ← 5 5 ⍴ 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 1 1 0 0 0 0 0 0
life grid
life life grid
Run life on it a few times and watch the pattern walk.
Step back and notice what's absent from that one line: no loops, no row-and-column indexes, no if statements, no special handling for cells at the edge (rotation wraps around, so the grid is a torus — the left edge neighbors the right, like Pac-Man's screen). The program isn't instructions for updating a grid. It's a description of what the next generation is. That's the APL worldview: say what the answer is, in terms of transformations on whole structures, and let the machine sweat the details.
Why this matters beyond APL
APL never conquered the world, but its big idea did. The notion that you should operate on whole arrays at once — that 2 × prices beats a loop — went on to shape an enormous amount of modern computing:
- Spreadsheets are array programming in disguise: a formula filled down a column is an operation applied to a whole vector.
- NumPy, the numerical foundation of the Python ecosystem, is explicitly in this lineage; its "broadcasting" is the descendant of APL's rule that a single number combines with an array of any size.
- The software behind modern AI — frameworks like PyTorch and JAX — is array programming through and through. Neural networks are, at bottom, arithmetic on gigantic arrays, and the mental habits this tutorial has been building (transform the whole structure; count by summing masks; shift the world instead of looping over it) are exactly the habits that field runs on.
Learn APL and you're not learning a curiosity. You're learning the pure, concentrated form of an idea you'll meet again and again — usually watered down.
Where to go next
- tryapl.org has built-in interactive lessons — a natural next step from here.
- APL Wiki is the community encyclopedia: every symbol, lots of learning paths.
- Dyalog APL is free for personal use if you want a full environment on your own machine.
- "Mastering Dyalog APL" by Bernard Legrand is the standard full-length book, available free as a PDF from Dyalog.
- When you're comfortable, look at J and BQN — modern languages by APL's inventor and its community, respectively, that carry the same ideas forward with different design choices.
A fair warning and a promise: APL rewires how you think about problems, and the rewiring is permanent. You'll find yourself looking at a loop in some other language and thinking, "that's just +/." That reflex — seeing the whole-array operation hiding inside the step-by-step procedure — is the real thing this strange, beautiful language has to teach.
Speaking & typing reference
Everything the converter understands, the backtick shortcuts on the APL line, and what each
symbol means. The round keys in the dock (⌨ symbols) insert these too. Single letters
(b–z) pass through as variable names — “x assign iota five” gives
x←⍳5. Words the converter doesn't know are shown struck out and skipped.