· 6 min read ·

The Language That Fits in Your Head: What Arthur Whitney's Philosophy Demands

Source: lobsters

A thread on Lobsters asks which languages support Arthur Whitney style programming, using the ksimple project as a reference point. The question is worth taking seriously, because Whitney style is not just a visual preference for dense code. It is a specific set of design constraints, and most modern languages fail them by construction.

What Whitney Style Actually Means

Arthur Whitney built his career on a direct lineage from APL. He worked at I.P. Sharp Associates alongside Ken Iverson in the early 1980s, then designed A+ at Morgan Stanley, then founded Kx Systems in 1993 to develop K and eventually kdb+. The K language, now on its seventh major revision, is the clearest expression of his design philosophy.

The core of that philosophy is this: every primitive operation maps to a single ASCII character, evaluation is right-to-left with uniform precedence, and arrays are the fundamental data type. There are no loops, no type declarations, and no named keywords for array operations.

/ sum
+/ 1 2 3 4 5

/ running sum (scan)
+\ 1 2 3 4 5

/ word frequency count
{x!#:'=x}" the cat sat on the mat"

/ fibonacci: 10 iterations starting from 0 1
{x,+/-2#x}/[8;0 1]

The last example generates a Fibonacci sequence by repeatedly applying a function that appends the sum of the last two elements. # is count/take, -2#x takes the last two elements, +/ sums them, , appends. The whole thing is one expression.

This density is not a stunt. Whitney has described his goal as making the language small enough to fit entirely in working memory, not just the interpreter, but the complete mental model. With roughly 20 primitives and 6 adverbs (higher-order operators like / for fold, \ for scan, ' for each), you can hold all of K in your head simultaneously. Once you do, every program becomes readable at a glance.

The ksimple Lesson

The ksimple project implements a K-like array data model in C using preprocessor macros. Its educational value is showing what the K runtime actually consists of: tagged unions, arena allocation, reference counting, and a dispatch table.

The C macro technique centers on _Generic (C11), which allows compile-time type dispatch:

#define ADD(a, b) _Generic((a),          \
    int:   _Generic((b),                  \
               int:   iadd(a, b),         \
               float: fadd((float)a, b)), \
    float: fadd(a, (float)(b)),           \
    default: array_add(a, b)              \
)

Combine this with X-macro tables for the verb dispatch table, statement-expression macros for temporary array construction, and a simple bump allocator for the arena, and you have the mechanical skeleton of a K interpreter in a few hundred lines.

The important limitation: C’s preprocessor tokenizes before macro expansion, so you cannot rebind the actual + - * symbols to your array operations. ksimple uses short alphabetic names instead. You get Whitney semantics without Whitney syntax. This gap matters, because a significant part of what makes K programs dense is that the operations use the exact symbols you already associate with arithmetic. +/ summing an array reads naturally once you know the conventions. FOLD(iadd, 0, arr) does not.

The Language Family That Can Actually Do This

APL and its descendants are the only languages where Whitney style is native, not approximated.

APL (1966, Kenneth Iverson) invented the paradigm, using a custom character set: for index generation, for shape, ⌊⌈ for floor and ceiling, ¨ for each, +.× for matrix multiply as a generalized inner product.

J (1990, Roger Hui and Iverson) redesigned APL to use only ASCII, relying on digraphs. +/ for sum, # for tally, {. for head, <. for floor. J introduced the notion of “trains”: the expression (f g h) y means (f y) g (h y), a fork that composes three functions without naming any intermediate value. This is tacit programming taken to a logical extreme.

BQN (2020, Marshall Lochbaum) is the most systematically designed modern entry. It uses Unicode glyphs like APL but with a cleaner grammar that distinguishes subjects, functions, and modifiers syntactically. The arguments 𝕨 and 𝕩 are named rather than implied by position, which helps readability without sacrificing density.

Uiua (2023) pushes further than K in some dimensions: it is stack-based, with no named local variables at all. Everything operates on a stack, and functions are pure transformations of that stack. This is a different flavor of point-free programming than J’s trains, but achieves similar density.

Languages That Get Part of the Way

Haskell comes closest among mainstream languages. Operators are first-class, any two-argument function can be used infix with backticks, and symbol sequences are valid operator names. The Data.Vector and hmatrix libraries use this to reasonable effect:

-- dot product
dot xs ys = sum $ zipWith (*) xs ys

-- matrix-vector multiply (hmatrix)
result = matrix #> vector

-- point-free scan
runningSums = scanl1 (+)

The limitation is that Haskell’s type system, even with inference, generates verbosity at module and function boundaries. Idiomatic Haskell annotates types explicitly. The compiler catches more errors, but the notation drifts away from Whitney density.

Raku has a legitimately interesting hyper-operator system. @a >>+<< @b applies + element-wise across two arrays. Reduction meta-operators like [+] for sum and [\+] for running sum are direct APL analogues. Users can define new operators using arbitrary Unicode symbols. But Raku is a maximalist language, the philosophical opposite of Whitney’s minimalism. The array features are one part of an enormous system.

Nim, D, and Rust all support operator overloading through their trait or type systems, and their macro facilities can build array DSLs. Rust’s ndarray crate achieves element-wise operations with &a + &b syntax. But the ownership model introduces friction: each intermediate array value must be owned or borrowed explicitly, which forces notational weight on exactly the operations that Whitney style wants to make invisible. You can implement Whitney semantics in Rust; you cannot implement Whitney syntax.

The Design Requirements

Stripping the survey down to a set of requirements, a language supports Whitney style if it provides:

  1. Overloadable primitive operators (not just methods named add), so that + can mean element-wise array addition.
  2. Uniform precedence or right-to-left evaluation, eliminating the need to memorize or annotate precedence.
  3. Array orientation as the grammar, not as a library. The difference between sum(array) and +/array is not just spelling; it is whether arrays are first-class in the language’s evaluation model or bolt-on through a library call.
  4. Tacit/point-free composition without mandatory argument naming, so that function composition is cheaper notionally than explicit lambda.
  5. Minimal annotation burden at the use site. Type declarations, lifetime annotations, and error-handling syntax all pull density down.

Modern systems languages fail requirement five almost by design. Rust’s ownership system and Zig’s explicit error propagation are deliberate rejections of the “programmer’s mental model is sufficient” stance that Whitney’s design assumes. Both positions are internally consistent. Rust is right that ownership annotations prevent a class of bugs. Whitney is right that annotation verbosity introduces a class of bugs by making programs harder to read.

The disagreement is about what class of software you are building. Financial tick data processing, Whitney’s actual use case, has a different error profile than an operating system kernel. kdb+ runs single-threaded per process and avoids the concurrency safety problem that motivates much of Rust’s complexity. The fact that they reach different conclusions does not make either design wrong.

Where Array Thinking Won Anyway

There is a separate observation worth making about the broader ecosystem. The array-oriented paradigm that Whitney inherits from Iverson has won in practice even where Whitney-style syntax has not. NumPy, pandas, R, MATLAB, and GPU compute shaders are all organized around the principle that operations apply uniformly over arrays without explicit loops. The mental model is exactly APL’s; the notation is Python or R.

This means the question of which languages support Whitney style has two answers. If you mean the notation, the terse ASCII expressions and single-character primitives, the answer is the APL family plus a few exotic newer entrants. If you mean the underlying computational model, array orientation is now the organizing principle of scientific computing, data engineering, and GPU programming across nearly every major language ecosystem.

Witney built a language small enough to fit in your head. The ideas inside it turned out to be large enough to shape the field.

Was this interesting?