Est. 2006 Advanced

Cat

Cat is a statically typed, stack-based pure functional language created by Christopher Diggins - a typed descendant of Joy, with no variables at all, designed as an intermediate language for optimization and verification.

Created by Christopher Diggins

Paradigm Concatenative (function-level), stack-based, pure functional - programs are built by composing functions rather than applying them to named arguments, and every expression denotes a function from one stack to another
Typing Static and strong, with full type inference. The v2 type system is a higher-rank parametric polymorphic system using row polymorphism over the stack, inferred without any user annotations; the earlier v1 implementation treated static typing as optional
First Appeared 2006 - first described publicly by Christopher Diggins in a weblog post on Artima dated May 13, 2006
Latest Version Cat v2, a TypeScript reimplementation; the last commit to the public repository is dated January 4, 2018. The original C# implementation (v1) was frozen in 2008 at v1b4

Cat is a statically typed, stack-based, pure functional programming language created by Christopher Diggins. It has no variables. It has no argument lists, no let, no parameters, no names for values of any kind. A Cat program is a sequence of instructions, each of which takes one stack and returns another, and putting two instructions side by side means composing them. That is the whole model.

What makes Cat more than a Joy clone is that it is typed, and typed without asking the programmer for anything. Cat infers a type for every expression, where a type describes what a function does to the shape of a stack, and it rejects programs that would underflow the stack or leave incompatible values on the branches of a conditional - all before running a single instruction.

The language was never intended to be a general-purpose programming language for humans writing applications. Diggins designed it as an intermediate language: something a compiler could target, verify, and optimize on the way down to a real machine.

History and Origins

Cat first appears publicly in a post to Diggins’ Artima weblog dated May 13, 2006. The framing there is telling. Cat is introduced not as a language to learn but as a compilation target, one that happened to sit between Joy and Microsoft’s MSIL. The argument was that high-level functional optimizations are easy to apply to a composition-based program and nearly impossible to recover once the program has been lowered to assembly-level instructions - so a compiler should pass through something like Cat first.

The direct ancestor is Joy, Manfred von Thun’s concatenative language, which is itself a descendant of Forth by way of Backus’s FP. Joy showed that you could build a complete functional language out of stack manipulation and quotation, with no variables at all. What Joy did not have was static types; it checked at runtime. Cat’s contribution was to keep Joy’s semantics and add a type system, which is why Cat has been summarised as “Forth meets Haskell.”

The language reached a wider audience in May 2008, when Diggins published Cat: A Functional Stack-Based Language in Dr. Dobb’s Journal. That article is still the most complete introduction to Cat v1 - quotations, partial application, higher-order combinators, metadata comments in a YAML-flavoured syntax that doubled as automated tests, and worked examples including quicksort and a MapReduce implementation.

Then it stopped. The v1 implementation - written in C#, running only on Windows, hosted on Google Code - was frozen in 2008 at v1b4. An embedding of Cat in Scheme and an online JavaScript interpreter had also been released, but the project went quiet for eight years.

The v2 rewrite

In October 2016, Diggins opened a GitHub repository for Cat; the first commit is annotated as the first since the Google Code v1b4 of 2008. Real work began in December 2017, with a complete reimplementation in TypeScript, compiled to ES5-compliant JavaScript so it would run anywhere rather than only on Windows.

The rewrite was not just a port. The specification was simplified, and the type system - which Diggins described as having originally been “a playground for various ideas” - was formalized properly. His own account of the intervening decade is that interest in Cat had settled on two things: the simple semantics, and the “deceptively simple type algorithm,” which he says he only later recognised as a higher-rank polymorphic type system.

The type checker was extracted into its own package, cdiggins/type-inference, explicitly so it could be reused by other JavaScript- or TypeScript-targeting language projects. Development ran for roughly two weeks. The last commit is dated January 4, 2018.

Design Philosophy

Composition instead of application

The central claim of concatenative programming, and Cat’s inheritance from Joy, is that program construction should be function composition rather than function application. In a conventional language you write f(g(x)) - you apply functions to arguments. In Cat you write g f, and juxtaposition is composition. There is no x.

The consequence is that any contiguous chunk of a Cat program is itself a valid function, and can be factored out and given a name with no rewriting whatsoever. That property - refactoring by cutting on any boundary - is the thing concatenative programmers tend to point at first.

Everything is a function on stacks

Cat takes this further than it might sound. Literals are functions too: 1 is the function that takes a stack and returns that stack with 1 pushed on it. Quotations are functions that push functions. There is exactly one kind of thing in the language.

Optimization as the design goal

Because a Cat program is a composition, program transformations are algebraic rewrites over a sequence. There are no environments to reason about, no aliasing, no order-of-evaluation questions. Diggins’ pitch was that this makes inlining, partial evaluation and verification structurally easy - the v1 C# implementation shipped type checking, inference, inlining and partial evaluation as part of the toolchain.

Key Features

Eight primitives

Cat v2 defines a core set of eight general-purpose primitive instructions, each with its type written in Cat’s own notation:

apply   : (('S -> 'R) 'S -> 'R)
quote   : ('a 'S -> ('R -> 'a 'R) 'S)
compose : (('B -> 'C) ('A -> 'B) 'S -> ('A -> 'C) 'S)
dup     : ('a 'S -> 'a 'a 'S)
pop     : ('a 'S -> 'S)
swap    : ('a 'b 'S -> 'b 'a 'S)
cond    : (Bool 'a 'a 'S -> 'a 'S)
while   : (('S -> Bool 'R) ('R -> 'S) 'S -> 'S)

A trivial program, from the project’s own readme: 6 7 dup mul sub leaves the value 43 on top of the stack.

Quotations

A quotation is an expression in brackets - [1 add] - which pushes that expression onto the stack as a value to be executed later, with apply or dip. This is how Cat gets first-class functions without ever naming a parameter. Quotations can be built at runtime by composing other quotations, which is how papply implements partial application.

Row-polymorphic types

Cat’s type notation describes a transformation between stack configurations. The terms left and right of the arrow are the stack before and after. Crucially, the last term on each side stands for “the rest of the stack” - a type variable representing everything the function does not touch. That is row polymorphism, and it is what lets a function like dup be given one type that works no matter how deep the stack is beneath it.

Identifiers prefixed with an apostrophe are type variables, which may be bound to any type including polymorphic functions.

A standard library derived from the primitives

Cat’s stack-shuffling vocabulary is not built in; it is defined. From the v2 standard library:

dip      = { swap quote compose apply }
rcompose = { swap compose }
papply   = { quote rcompose }
dipd     = { swap [dip] dip }
popd     = { [pop] dip }
popop    = { pop pop }
dupd     = { [dup] dip }
swapd    = { [swap] dip }
rollup   = { swap swapd }
rolldown = { swapd swap }

Every one of these gets a type inferred automatically. papply, for example, infers as ('t0 ('t0 't1 -> 't2) 't3 -> ('t1 -> 't2) 't3) - it consumes a value and a function and hands back a function with that value already bound.

Notably, dip was a primitive early in the v2 rewrite and was removed on December 29, 2017, once it could be defined in terms of the basic forms.

Higher-rank polymorphism, fully inferred

Cat v2 supports higher-rank parametric polymorphism without recursive types, and infers all of it - no annotations required anywhere. The formal statement of the primitive types uses explicit quantifiers and nested pairs for stacks:

apply   : !R.(!S.((S -> R) S) -> R)
quote   : !S!a.((a S) -> (!R.(R -> (a R)) S))
compose : !A!C!S.(!B.((B -> C) ((A -> B) S)) -> ((A -> C) S))

This has a concrete consequence the project documents explicitly: Cat cannot be embedded in a language limited to rank-1 polymorphism, such as Haskell or ML, because those systems cannot infer the type of the expression quote dup.

Grammar

Cat’s syntax is small enough to state in one page. The v2 parser is written with the Myna TypeScript parsing library and recognises quotations, integers, booleans, identifiers, type expressions, define with an optional type signature, and extern declarations. That is the entire language.

Evolution

Cat v1Cat v2
Released2008 (frozen at v1b4)Developed Dec 2017 - Jan 2018
ImplementationC#TypeScript → ES5 JavaScript
PlatformWindows onlyAnywhere JavaScript runs
TypingOptional static typingStatic, fully inferred, higher-rank
HostingGoogle CodeGitHub, MIT licensed
ScopeBroad - “a playground for various ideas”Deliberately narrowed

The most interesting thing about the two versions is what got thrown away. V1 accumulated features across several years of experimentation. V2 kept eight primitives and a type system, and dropped nearly everything else. It is a rare case of a language author returning after a decade and making the language decisively smaller.

Current Relevance

Cat is dormant. The repository has not been touched since January 2018, the wiki entry describing it was last revised in early 2020, and there is no package ecosystem, no community, and no production software written in it. Nobody should pick Cat for a project today.

What survives is the idea. The problem Cat set out to solve - how do you give static types to a language where every function silently consumes and produces an unbounded stack - has an answer that Cat states cleanly, and that answer is row polymorphism plus higher-rank inference. Typed concatenative languages designed since operate in territory Cat helped map; the row-variable notation in particular is now common vocabulary for the problem. The type-inference package was deliberately factored out to make that transfer easy.

The repository remains available under the MIT License and has accumulated roughly 285 GitHub stars as of 2026 - a reasonable measure of a language nobody uses but a fair number of people found worth reading.

Why It Matters

Cat is a good example of a language whose value is entirely in its argument rather than its adoption. Three things it did are worth keeping:

  1. It made a case for concatenative languages as compiler infrastructure. Not “here is a nicer language,” but “here is a representation in which optimization is easy,” which is a claim about compilers, not about taste.
  2. It typed Joy. Joy demonstrated that variable-free functional programming works; Cat demonstrated that it can be statically checked without giving up inference or annotating anything.
  3. It shows how far a handful of primitives goes. Eight instructions, plus quotation, generate the entire stack-manipulation vocabulary - and every derived definition types itself.

For anyone interested in how programming languages get smaller rather than larger, Cat’s v1-to-v2 arc is an unusually clean case study: an author with ten years of hindsight, deleting most of his own language and keeping the part that turned out to be the idea.

Timeline

2006
Christopher Diggins introduces Cat in a post to his Artima weblog dated May 13, 2006, describing it as a pure functional stack-based language inspired by Joy that targets the Microsoft Intermediate Language (MSIL). The pitch from the outset is not that people should write applications in Cat, but that a concatenative language makes an unusually good intermediate representation, because composition-based programs are easy to rewrite and optimize
2008
Diggins publishes Cat: A Functional Stack-Based Language in the May 2008 issue of Dr. Dobb's Journal, presenting the language to a mainstream programming audience. The article covers quotations, partial application via papply, the higher-order combinators apply, dip, if and while, and a row-polymorphic type system with Hindley-Milner style inference, illustrated with quicksort, MapReduce, factorial and Fibonacci
2008
Diggins circulates the paper Typing Functional Stack-Based Languages, which sets out the formal treatment of the type system behind Cat. It is the piece of the project with the longest reach - the typing of concatenative languages, rather than the language itself, is what later readers return to
2008
The original Cat implementation - written in C#, running only on Windows, and hosted on Google Code - reaches v1b4 and is frozen. An embedding of Cat in Scheme and an online Cat interpreter written in JavaScript are also released during the v1 era, alongside the primary open-source C# interpreter. The language sits untouched for eight years
2016
Diggins creates the cdiggins/cat-language repository on GitHub on October 5, 2016. Its first commit is labelled as the first since v1b4 on the Google Code version in 2008, and it initially carries the archived C# sources
2017
Work on Cat v2 begins in December 2017: a complete reimplementation in TypeScript compiled to ES5-compliant JavaScript. The first v2 commit, dated December 20, 2017, notes that the language is blocked on the type-inference module - the type checker was pulled out into a standalone package, cdiggins/type-inference, so it could be reused by other projects. Within days the standard library validates, and dip is demoted from a primitive to a definition in terms of swap, quote, compose and apply
2018
The v2 readme is finalized in the first days of January 2018, documenting eight primitives, the row-polymorphic type syntax, the formalized higher-rank types, and a grammar written with the Myna parser library. The last commit to the repository is dated January 4, 2018. Cat has been dormant since, though the MIT-licensed repository remains online and has continued to accumulate stars
2020
The Cat entry on the concatenative.org wiki - the community reference for stack-based languages - is last revised on February 28, 2020, listing Cat as maintained by its designer and pointing at the TypeScript implementation. The language survives mainly as a reference point in discussions of typed concatenative programming rather than as a tool in use

Notable Uses & Legacy

Dr. Dobb's Journal

Cat's widest audience came from the May 2008 Dr. Dobb's Journal article, which used the language to argue a specific case: that a small typed concatenative language is a better compiler intermediate representation than a stack machine bytecode, because high-level rewrites like inlining and partial evaluation stay expressible after lowering. The article was reportedly the language's widest single exposure to a mainstream programming audience.

The type-inference package

The most concretely reusable artifact of the project. Cat v2's type checker was deliberately built as a standalone TypeScript package (cdiggins/type-inference) rather than as part of the interpreter, so that the higher-rank inference algorithm could be lifted into other language projects targeting JavaScript or TypeScript, or ported elsewhere. The Cat v2 readme separately documents why Cat cannot be embedded in a rank-1 polymorphic host such as Haskell or ML.

Research on typing concatenative languages

Cat is frequently cited when the question of how to statically type a stack language comes up. The 2008 paper Typing Functional Stack-Based Languages and the row-polymorphic notation Cat uses - where every function type carries a variable standing for the untouched rest of the stack - are commonly referenced in discussions of later typed concatenative designs.

The concatenative programming community

On concatenative.org, the community wiki that catalogues Forth, Joy, Factor and their relatives, Cat occupies the slot for the typed, inferred branch of the family. Its documented primitive set and derived standard library serve as a compact worked example of how a concatenative language bootstraps stack shuffling from a handful of combinators.

Teaching and intermediate-language experiments

Diggins proposed Cat for embedded targets, for teaching the fundamentals of program composition, and as an intermediate language for compiler projects. The teaching case is arguably the one that held up best: with eight primitives, no variables, no syntax to speak of and fully inferred types, Cat is about as small a vehicle as exists for demonstrating that a program is a composition of functions.

Language Influence

Influenced By

Running Today

Run examples using the official Docker image:

docker pull
Last updated: