Paradigm LostTOTAL BY DEPARTMENT · MODEL 1935—2026 · 11 EXHIBITS
powerreadycheck
Eleven ways to add up a column of numbers

The same problem,
ninety years apart


Every program on this page does one thing: total the amounts by department and print a report. The problem never changes. What changes is what a programmer thought a program was — a wiring diagram, a deck of cards, a stack, a matrix, a set of facts, a sentence.

Each exhibit runs its own execution model in the console beneath it, because these machines do not merely spell one algorithm differently. They hold different things in their hands while they work.

Read down and something odd happens. The 1935 machine and the 1974 database express the same idea, and the forty years in between are spent writing by hand what both of them got for free.

The deck

12 cards · 24 columns punched · input to all eleven

A payroll register from a firm that never existed, staffed entirely by people who did. Twelve 80-column cards, punched in three fields: name in columns 1–10, department in 11–18, amount in 19–24 with an implied decimal. Every exhibit below reads exactly this.

BACKUS ASSEMBLY 1267500000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999
BACKUS, J.126.75
IVERSON ASSEMBLY 1093000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999
IVERSON, K.109.30
ROSSUM ASSEMBLY 881500000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999
ROSSUM, G.88.15
CODD PAYROLL 976000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999
CODD, E.97.60
HOLLERITH PAYROLL 1184000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999
HOLLERITH, H.118.40
HOPPER PAYROLL 1342500000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999
HOPPER, G.134.25
AHO SHIPPING 1042000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999
AHO, A.104.20
KAY SHIPPING 998500000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999
KAY, A.99.85
KERNIGHAN SHIPPING 1119500000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999
KERNIGHAN, B.111.95
WEINBERGER SHIPPING 937000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999
WEINBERGER, P.93.70
KOWALSKI TOOLROOM 1155000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999
KOWALSKI, R.115.50
MOORE TOOLROOM 1420000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999
MOORE, C.142.00

Presorted on the department field — four of the eleven programs below simply will not work otherwise. Four departments, twelve records, grand total 1341.65. Departments: ASSEMBLY · PAYROLL · SHIPPING · TOOLROOM.

1935Exhibit 01/11

There is no program

IBM 407 Accounting Machine · IBM 082 Sorter · no stored instruction of any kind

A program is a shape you wire into a panel. It has no first step, because it happens to every card at once.

Control panel wiring listtraced, not emulated
*  407 CONTROL PANEL — MINOR TOTALS ON DEPT
*  DECK MUST FIRST PASS THE 082 SORTER ON COLS 11-18

   FROM                        TO
   READ EXIT   1-10   NAME  -> PRINT ENTRY  1-10
   READ EXIT  11-18   DEPT  -> PRINT ENTRY 20-27
   READ EXIT  11-18   DEPT  -> COMPARING ENTRY B
   READ EXIT  19-24   AMT   -> COUNTER 4A ADD
   COMPARING EXIT  UNEQUAL  -> PROGRAM START (MINOR)
   COUNTER 4A TOTAL EXIT    -> PRINT ENTRY 30-38
   COUNTER 4A TOTAL EXIT    -> COUNTER 4A RESET

There is no source listing for this exhibit because there is no source. The behaviour of the machine is the set of wires in the panel, and to change the report you unplug a cord and plug it somewhere else. A 407 program was a physical object you carried to the machine room in a frame.

The whole report hangs on one cord: COMPARING EXIT UNEQUAL to PROGRAM START. The 407 compares each card’s department field against the one before it, and when they differ it fires a control break — take the counter’s accumulated total, print it, clear the counter, resume.

That comparison only works because the deck arrived sorted, and the sort is not part of the program at all. It happened on a different machine, in a different room, possibly on a different day. The precondition lives in the world rather than in the code, which is the single most alien thing about this exhibit.

FreeNo loop, no counter management, no iteration variable. The card feed is the loop, and it is made of metal.
CostlyAnything that is not a break on a sorted field. Two independent groupings means two passes and two wirings.
At rest. This console shows what the paradigm actually does between the source and the report.000 / 018
407 CONTROL PANEL — MINOR TOTALS ON DEPTREAD EXIT 1-10 · NAMEREAD EXIT 11-18 · DEPTREAD EXIT 19-24 · AMTCOMPARING EXIT · UNEQUALCOUNTER 4A · TOTAL EXITPRINT ENTRY 1-10PRINT ENTRY 20-27COMPARING ENTRY BCOUNTER 4A · ADDPROGRAM START (MINOR)PRINT ENTRY 30-38COUNTER 4A · RESET
IBM 1403 · line printer
— carriage at home, no output —
ConsolePanel bay
1957Exhibit 02/11

Write the break out longhand

FORTRAN II on the IBM 704 · fixed form, columns 7–72 · John Backus and team

A program is a sequence of statements with numbers on them, and the numbers are where you go.

FORTRAN IItraced, not emulated
C     TOTAL BY DEPARTMENT
C     CARDS PRESORTED ON DEPT CODE, COLS 11-12
      SUM   = 0.0
      GRAND = 0.0
      LAST  = 0
      DO 40 J = 1, 12
      READ 100, N1, N2, KODE, AMT
      IF (LAST) 10, 10, 20
   10 LAST = KODE
   20 IF (KODE - LAST) 30, 35, 30
   30 PRINT 200, LAST, SUM
      GRAND = GRAND + SUM
      SUM   = 0.0
      LAST  = KODE
   35 SUM = SUM + AMT
   40 CONTINUE
      PRINT 200, LAST, SUM
      GRAND = GRAND + SUM
      PRINT 300, GRAND
      STOP
  100 FORMAT (2A4, I2, F7.2)
  200 FORMAT (1H , A8, F9.2)
  300 FORMAT (1H0, 11HGRAND TOTAL, F9.2)
      END

Everything the 407 did structurally, FORTRAN makes you say. The comparison, the print, the reset, the resume — four cords become nine statements, and the statement numbers are the only thing holding them together.

IF (KODE - LAST) 30, 35, 30 is the arithmetic IF: evaluate the expression, then branch to one of three labels depending on whether it came out negative, zero or positive. It is a three-way GOTO, and it was the primary conditional in the language.

Note that the department is an integer code rather than a name. FORTRAN II had no character type; text existed only as Hollerith constants inside FORMAT statements, which is why the literal 11HGRAND TOTAL has to carry its own length as a prefix. The data had to be numbered before it could be processed, and somebody in the building kept the codebook.

And there at the bottom: the duplicated PRINT 200 after the loop. The last department has no successor to differ from, so its total never breaks. Every control-break program written between 1957 and roughly 1985 contains this same small act of remembering, and the ones that forgot silently dropped a department.

FreeArithmetic, arrays, a loop you can nest. Genuinely general for the first time in history.
CostlyText of any kind. And the thing the 407 did for free is now yours to get right, once per program, forever.
At rest. This console shows what the paradigm actually does between the source and the report.000 / 018
LAST—
SUM0.00
GRAND0.00
IBM 1403 · line printer
— carriage at home, no output —
ConsoleDisplay bay
1960Exhibit 03/11

The report is a data declaration

COBOL-60 · the CODASYL committee · Grace Hopper’s FLOW-MATIC as the direct ancestor

A program is a description of records, and then some sentences about them.

COBOLtraced, not emulated
       DATA DIVISION.
       FILE SECTION.
       FD  PAY-FILE  LABEL RECORDS ARE OMITTED.
       01  PAY-CARD.
           05  PC-NAME      PIC X(10).
           05  PC-DEPT      PIC X(8).
           05  PC-AMOUNT    PIC 9(4)V99.
       WORKING-STORAGE SECTION.
       77  WS-PREV-DEPT     PIC X(8)     VALUE SPACES.
       77  WS-DEPT-TOTAL    PIC 9(6)V99  VALUE ZERO.
       77  WS-GRAND-TOTAL   PIC 9(7)V99  VALUE ZERO.
       01  RPT-LINE.
           05  RL-DEPT      PIC X(14).
           05  RL-TOTAL     PIC ZZZ,ZZ9.99.

       PROCEDURE DIVISION.
       MAIN-LINE.
           PERFORM READ-A-CARD.
           PERFORM PROCESS-CARD UNTIL END-OF-FILE.
           PERFORM PRINT-BREAK.
           MOVE 'GRAND TOTAL' TO RL-DEPT.
           MOVE WS-GRAND-TOTAL TO RL-TOTAL.
           WRITE RPT-LINE AFTER ADVANCING 2 LINES.
           STOP RUN.

       PROCESS-CARD.
           IF PC-DEPT NOT = WS-PREV-DEPT
               AND WS-PREV-DEPT NOT = SPACES
               PERFORM PRINT-BREAK.
           MOVE PC-DEPT TO WS-PREV-DEPT.
           ADD PC-AMOUNT TO WS-DEPT-TOTAL.
           PERFORM READ-A-CARD.

       PRINT-BREAK.
           MOVE WS-PREV-DEPT TO RL-DEPT.
           MOVE WS-DEPT-TOTAL TO RL-TOTAL.
           WRITE RPT-LINE.
           ADD WS-DEPT-TOTAL TO WS-GRAND-TOTAL.
           MOVE ZERO TO WS-DEPT-TOTAL.

The control break is identical to FORTRAN’s — same comparison, same reset, same forgotten-final-group trap. What COBOL adds is somewhere to put the layout.

PIC ZZZ,ZZ9.99 is an edited picture, and it is the most underrated idea in the language: it declares that this field, when something is moved into it, will suppress leading zeros, insert a comma at the thousands and fix two decimals. The formatting is a property of the destination, not an act of the code. Modern printf is a step backwards from this.

COBOL is mocked for its verbosity, but look at what the verbosity buys. A person who does payroll and not programming can read ADD PC-AMOUNT TO WS-DEPT-TOTAL and audit it. That was the explicit design goal, and by that measure it worked for sixty years.

FreeRecord layout, decimal arithmetic that is actually decimal, and report formatting as declaration.
CostlyStill writing the break by hand. And the DATA DIVISION is where the program’s real complexity goes to hide.
At rest. This console shows what the paradigm actually does between the source and the report.000 / 018
WS-PREV-DEPT—
WS-DEPT-TOTAL0.00
WS-GRAND-TOTAL0.00
IBM 1403 · line printer
— carriage at home, no output —
ConsoleDisplay bay
1964Exhibit 04/11

The loop you are not allowed to write

RPG II · IBM System/360 Model 20 · a deliberate descendant of the 407 panel

A program is a set of specifications, and the machine supplies the control flow.

RPG II specification sheetstraced, not emulated
     H*  TOTAL BY DEPARTMENT                       RPG II
     FPAYCARD IP  F      24            READ01  SYSIPT
     FREPORT  O   F      80            PRINTER
    *
    *  I-SPEC: FIELD DESCRIPTIONS. THE "L1" IS THE WHOLE TRICK.
     IPAYCARD AA  01
     I                          1   10 NAME
     I                         11   18 DEPT      L1
     I                         19   24 2AMT
    *
    *  C-SPEC: THE ONLY LINES YOU ACTUALLY WROTE
     C   01            AMT       ADD  DTOT      DTOT    72
     C   L1            DTOT      ADD  GTOT      GTOT    82
    *
    *  O-SPEC: WHAT PRINTS, AND ON WHICH INDICATOR
     OREPORT  T    L1
     O                DEPT             20
     O                DTOT   J         38
     OREPORT  T    LR
     O                'GRAND TOTAL'    20
     O                GTOT   J         38

Look for the loop. There is not one. RPG has a fixed program cycle built into the runtime: read a card, set indicators, do total-time output, run the calculation specs, do detail output, repeat until the hopper is empty. You do not write it and you cannot change it.

The two characters L1 in columns 59–60 of the input spec declare that DEPT is a control field at level one. From that single annotation the cycle derives everything — it saves the previous value, compares on every card, sets the L1 indicator when it changes, and runs total-time output before the new card’s detail processing. The control break has become a declaration again, twenty-nine years after the 407.

LR is last-record, set automatically at end of file, which means RPG cannot have FORTRAN’s dropped-final-group bug: the last break is not something a programmer is able to forget.

The price is total. Your program has one shape, and programs that do not fit the cycle get written by fighting it; generations of RPG programmers have the scars. But for this problem — and this problem was most of commercial computing in 1964 — six lines do the work of COBOL’s forty.

FreeThe loop, the break, the previous-value save, the end-of-file total, and the report layout.
CostlyLiterally anything with a different control shape. There is no escape hatch, only the cycle.
At rest. This console shows what the paradigm actually does between the source and the report.000 / 042
The program cycle
1 · Read a cardthe runtime
2 · Set indicators, detect L1the runtime
3 · Total-time outputthe runtime
4 · Calculation specsyou wrote this
5 · Detail outputthe runtime
Fields and indicators
DTOT0.00
GTOT0.00
L1off
IBM 1403 · line printer
— carriage at home, no output —
ConsoleDisplay bay
1966Exhibit 05/11

The grouping is a matrix

APL\360 · Kenneth Iverson at IBM Research · notation from A Programming Language, 1962

A program is an expression. Control structure dissolves into the shape of the data.

APLtraced, not emulated
      ⍝  DEPT is a 12-row character matrix, AMT a 12-vector
      ⍝  U is the four distinct departments

      U ← ∪ DEPT

      T ← (U ∘.≡ DEPT) +.× AMT

      ⍝  and that is the program.
      ⍝  ∘.≡  builds a 4×12 boolean membership matrix
      ⍝  +.×  is the inner product: rows against amounts

      ⍝  the grand total, for completeness:
      +/T

The entire report is one line, and it contains no loop, no accumulator, no comparison against a previous value, and no dependence whatsoever on the order of the deck.

U ∘.≡ DEPT is an outer product: take every department name against every card’s department and produce a matrix of ones and zeros. That matrix is the grouping — row two is a mask selecting the payroll cards. Watch it build in the panel below.

Then +.×, the inner product, multiplies that matrix by the amount vector: exactly matrix multiplication, which means each row contributes an amount only where its mask is one. Grouping and summing turn out to be the same operation as linear algebra, and once you have seen that you cannot unsee it.

This is a different claim from every exhibit above it. FORTRAN and COBOL and RPG all agree that a program is a sequence of things happening to one card at a time. APL says the whole deck is a single value, and the program is a function of it.

FreeOrder-independence, no loop, no break, no reset. The 4×12 intermediate is the algorithm made visible.
CostlyThat intermediate is real: this materialises a matrix proportional to cards × groups. Fine for twelve cards, less fine for twelve million.
At rest. This console shows what the paradigm actually does between the source and the report.000 / 019
BIRCHHAKKWKM
ASSEMBLY
PAYROLL
SHIPPING
TOOLROOM
U — four rows, nothing compared yet
IBM 1403 · line printer
— carriage at home, no output —
ConsoleDisplay bay
1970Exhibit 06/11

The stack is the whole machine

Forth · Charles Moore · written to point radio telescopes, and then everything else

A program is a vocabulary. You extend the language downward until the problem is a word in it.

Forthexecutes here
VARIABLE SUM   VARIABLE GRAND   VARIABLE LAST

: BREAK    LAST @ .DEPT  SUM @ .MONEY  CR
           SUM @ GRAND +!   0 SUM ! ;

: RECORD   SWAP DUP LAST @ <> IF
                LAST @ -1 <> IF BREAK THEN
                LAST !
           ELSE DROP THEN
           SUM +! ;

: RUN      12 0 DO  I CARD RECORD  LOOP
           BREAK  ." GRAND TOTAL" GRAND @ .MONEY CR ;

This one genuinely executes. The panel below is a small token-threaded Forth running that exact source a word at a time, so you can watch the data stack fill and drain. Amounts are integer cents, because Forth of this era had no floating point and did not miss it.

There are no parameters and no local variables anywhere. RECORD receives its arguments because CARD left them on the stack, and it juggles them with SWAP and DUP. This is either liberating or appalling depending on the hour of the day.

The real idea is the colon. Every definition adds a word to the dictionary, and from that moment it is indistinguishable from a built-in — BREAK is now part of the language. You do not write a program in Forth so much as grow a language down towards the problem, which is why the top-level word is three lines long.

The control break is back to being hand-written, as it was in FORTRAN. But notice where it lives now: it is a named thing, defined once, and the last line reads almost like the RPG spec sheet two exhibits up.

FreeExtreme economy. This compiles to a few hundred bytes and needs no operating system underneath it.
CostlyStack juggling is a real cognitive tax, and the compiler will not help you — there are no types for it to check.
At rest. This console shows what the paradigm actually does between the source and the report.000 / 252
Data stack · top of stack first
12
Variables
SUM0.00
GRAND0.00
LAST—
IBM 1403 · line printer
— carriage at home, no output —
ConsoleDisplay bay
1972Exhibit 07/11

Say what a total is, not how to get one

Prolog · Alain Colmerauer at Marseille · with Robert Kowalski’s procedural reading of logic

A program is a set of true statements. Running it means asking a question.

Prologtraced, not emulated
%  the deck, as facts. amounts in cents.
pay(backus,     assembly, 12675).
pay(iverson,    assembly, 10930).
pay(rossum,     assembly,  8815).
pay(codd,       payroll,   9760).
pay(hollerith,  payroll,  11840).
pay(hopper,     payroll,  13425).
pay(aho,        shipping, 10420).
pay(kay,        shipping,  9985).
pay(kernighan,  shipping, 11195).
pay(weinberger, shipping,  9370).
pay(kowalski,   toolroom, 11550).
pay(moore,      toolroom, 14200).

%  a department total is the sum of the amounts in it.
total(Dept, Total) :-
    setof(D, N^A^pay(N, D, A), Depts),
    member(Dept, Depts),
    findall(A, pay(_, Dept, A), Amounts),
    sum_list(Amounts, Total).

%  the report is every solution to that.
?- forall(total(D, T), report_line(D, T)).

Nothing here describes a procedure. total(Dept, Total) is a claim about when two things stand in a relation, and the report is produced by asking for every pair that satisfies it. The engine does the searching.

findall(A, pay(_, Dept, A), Amounts) reads: collect every A such that somebody in this department was paid it. The underscore is an anonymous variable — the name is irrelevant to the question, so it does not get one.

Deck order is meaningless here, as it was for APL, but for a different reason. APL made order irrelevant by treating the deck as one value; Prolog makes it irrelevant by treating it as an unordered set of assertions. Both had to abandon the card feed to get there.

And the same program answers questions it was never written for. ?- total(shipping, T). asks about one department. ?- pay(N, D, A), A > 12000. asks who earns most. There is no main. There is a database of truths, and whatever you care to ask of it.

FreeOrder, grouping, iteration, and every query you did not think of when you wrote it.
CostlyKnowing what it will cost to run. The search strategy is the implementation’s business, right up until it is suddenly yours.
At rest. This console shows what the paradigm actually does between the source and the report.000 / 012
?- total(D, T).
IBM 1403 · line printer
— carriage at home, no output —
ConsoleDisplay bay
1974Exhibit 08/11

Name the thing the 407 was wired for

SEQUEL · Donald Chamberlin and Raymond Boyce at IBM San Jose · on Codd’s 1970 relational model

A program is a description of the answer. Someone else decides how to get it.

SQLtraced, not emulated
SELECT   dept,
         SUM(amount) AS total
FROM     payroll
GROUP BY dept
ORDER BY dept;

Four lines, and every one of them is a cord from the first exhibit. ORDER BY is the 082 sorter. GROUP BY is the comparing exit. SUM is counter 4A. The reset is so thoroughly implied that the language has no word for it.

This is the hinge of the whole page. Thirty-nine years after the accounting machine, and after four exhibits of programmers writing the sort and the break and the reset out by hand, somebody wrote the four ideas down as names and the problem stopped being a program.

What changed underneath is the interesting part. The 407 could only do this because a human had already sorted the deck; the query planner decides for itself whether to sort-and-break or build a hash table, and on a large enough table it picks the plugboard’s strategy for the plugboard’s reasons. Sorting in order to group never stopped being the right answer — it stopped being the programmer’s problem.

Codd’s claim in 1970 was that data has a structure independent of how any particular program wants to walk it. Nothing on this page before this exhibit believed that. Everything after it assumes it.

FreeThe loop, the break, the sort, the reset, the parallelism, and the choice of algorithm.
CostlyAnything that is not a set operation. And you cannot see what it did — that is the trade you are making.
At rest. This console shows what the paradigm actually does between the source and the report.000 / 019
BucketAccumulated
empty — nothing read yet
IBM 1403 · line printer
— carriage at home, no output —
ConsoleDisplay bay
1977Exhibit 09/11

The program cycle, with a Unix accent

awk · Alfred Aho, Peter Weinberger and Brian Kernighan at Bell Labs

A program is a set of rules: when you see this, do that. The reading is not your job.

awktraced, not emulated
{ total[$2] += $3 }

END { for (d in total)
        printf "%-14s%9.2f\n", d, total[d]
      printf "%-14s%9.2f\n", "GRAND TOTAL", sum }

Two rules. The first has no condition, so it runs on every line; the second runs at end of input. There is no loop in the source because awk supplies one — read a record, split it into fields, test each pattern, run the actions that match, repeat. Exactly as RPG did it in 1964.

total[$2] += $3 creates the bucket on first touch. Associative arrays were not a common language feature in 1977, and they are what let the grouping be one character of syntax instead of a data structure you have to build.

Compare this with the RPG spec sheet three exhibits up. Both declare per-record behaviour and let the runtime own the sequence; both have an automatic end-of-input hook, called END here and LR there. Two entirely separate traditions independently rediscovered the accounting machine’s shape, one in commercial data processing and one inside a research phone company.

And unlike every card-era exhibit, the deck order is irrelevant — because the hash table remembers what the control break had to be told.

FreeThe read loop, field splitting, the grouping structure, and the end-of-input hook. Two lines is the whole program.
CostlyOutput order: a for-in loop over an awk array is unordered, so the version above is quietly cheating.
At rest. This console shows what the paradigm actually does between the source and the report.000 / 019
BucketAccumulated
empty — nothing read yet
IBM 1403 · line printer
— carriage at home, no output —
ConsoleDisplay bay
1980Exhibit 10/11

There is no file to run

Smalltalk-80 · Alan Kay, Dan Ingalls and Adele Goldberg at Xerox PARC

A program is a live world of objects. You do not run it; you talk to it while it is already running.

Smalltalk-80traced, not emulated
| totals |
totals := deck
    inject: Dictionary new
    into: [:acc :card |
        acc at: card dept
            put: (acc at: card dept ifAbsent: [0]) + card amount.
        acc].

totals keys asSortedCollection do: [:d |
    Transcript show: (d paddedTo: 14);
               show: ((totals at: d) / 100) printString;
               cr].

"or, once you have taught the collection the idea:"

(deck groupedBy: [:card | card dept])
    collect: [:group | group inject: 0 into: [:a :c | a + c amount]]

You do not compile this. You select it inside a running image, press do it, and it happens to objects that were already alive — and that stay alive afterwards. The deck is not read from a file at the start of a run, because there is no start of a run.

[:acc :card | … ] is a block: an object that holds code, which you hand to the collection so that it can call you back. Every conditional and every loop in the language is built from this and nothing else. ifTrue: is a message sent to a boolean with a block as its argument, and that is not a metaphor or a teaching simplification.

The last stanza is the Smalltalk move. groupedBy: is not a language feature — it is a method somebody added to Collection one afternoon, inside the image, while the system was running, and from then on it was as native as anything Xerox shipped. This is the same instinct as Forth’s dictionary, ten years later and a great deal larger.

The consequence nobody expects: an image can be saved with your half-finished work still on the stack, mailed to a colleague, and resumed mid-thought on their machine. The program and its execution are the same artefact.

FreeUniformity. There are no statements and no privileged types — grouping is a message like any other.
CostlyVersion control, deployment, and explaining to anybody what the source of your program actually is.
At rest. This console shows what the paradigm actually does between the source and the report.000 / 019
BucketAccumulated
empty — nothing read yet
IBM 1403 · line printer
— carriage at home, no output —
ConsoleDisplay bay
2026Exhibit 11/11

Everything, and nothing to see

pandas · and its ancestors, all of them, invisible

A program is one line. What it does underneath is not a question you are expected to ask.

Pythontraced, not emulated
import pandas as pd

df = pd.read_fwf("payroll.txt",
                 colspecs=[(0,10),(10,18),(18,24)],
                 names=["name","dept","amount"])

print(df.groupby("dept")["amount"].sum())

One line does the work. It is a good line, it is the right line, and almost nobody who writes it could tell you what happens inside.

What happens inside is a hash aggregate — and if the frame is large enough, or the operation spills to disk, what happens inside is a sort followed by a control break, because that is still, in 2026, the correct algorithm when the groups do not fit in memory. The 407 was not doing a primitive version of this. It was doing this.

Look at colspecs=[(0,10),(10,18),(18,24)]. Those are the punched card’s column boundaries, and the function is called read_fwf — read fixed width formatted. Ninety years on, the deck is still a supported input format, and the columns have not moved.

This is not a lament. Layers that hide their machinery are how anything large gets built, and nobody should have to wire a panel to add up a column of numbers. But it is worth knowing that the thing being hidden is not complexity for its own sake. It is a sorter, a comparator and a counter, and somebody wired them together before the war.

FreeAll of it. Reading, parsing, typing, grouping, summing, formatting, and the choice of algorithm.
CostlyKnowing what it did — which matters exactly when the data gets big enough to care, and not one moment before.
At rest. This console shows what the paradigm actually does between the source and the report.000 / 019
BucketAccumulated
empty — nothing read yet
IBM 1403 · line printer
— carriage at home, no output —
ConsoleDisplay bay
The rhyme

Put the first exhibit next to the eighth. In 1935 you sorted the deck on an 082, then wired a comparing exit to a counter’s total exit so that a change in the department field would print a subtotal and clear the counter. In 1974 you wrote four lines.

1935 · wired082 sorter pass
compare DEPT ≠ DEPT
counter 4A total exit
counter 4A reset
≡
1974 · namedORDER BY dept
GROUP BY dept
SUM(amount)
—

These are the same four thoughts. The accounting machine expressed them as topology and the database expressed them as a name, and in both cases the programmer never writes the loop. The loop is the machine’s business.

Everything between them — FORTRAN, COBOL, the whole imperative middle — is people writing the sort and the break out longhand, because the machines of that era had learned to be general and forgotten how to be specific.

We did not go from imperative to declarative

The usual story is a ladder: machine code, then assembly, then procedures, then objects, then at long last the declarative styles, each rung an improvement on the last. Read this page from the top and that story falls apart.

We started declarative. We had to — the earliest machines were not machines you instructed, they were machines you configured, and a configuration has no time in it. A plugboard says what is true of every card. So does GROUP BY. So does an awk pattern, a Prolog clause, an APL matrix product.

Then the stored-program computer arrived and made everything possible, which meant it made nothing easy. For forty years the price of generality was that you wrote the loop, the comparison, the accumulator and the reset yourself, on every job, forever, and called the ones you got wrong bugs.

What SQL and awk and pandas recovered was not a new idea. It was the accounting machine’s idea, rebuilt on top of a general computer instead of underneath one — specificity bought back at the cost of an interpreter.

The control break was never lost, exactly. It was just, for a while, something you had to remember to do.