NoiseLang: Where N = 5 is a Dirac delta — Manu Martínez-Almeida
Systems<br>NoiseLang: Where N = 5 is a Dirac delta<br>July 6, 2026 · Manu Martínez-Almeida programming languagesprobabilitycompilersside project
During my telecommunications degree I took a<br>course on signals and noise, I spent a lot of evenings writing probability by hand: expectations,<br>variances, the odds of two random variables landing in some region. It always sucked, when I tried to run it on a computer, so much boilerplate.
That wish became NoiseLang. I started it about nine years ago, however, I never finished it.<br>Only recently, I brought it back thanks to AI tools and something far more ambitious than what I could have built alone<br>the first time.
Everything is a distribution
The whole language hangs on one idea, that every value is a probability distribution . A plain number is<br>a Dirac spike, a distribution with all its weight on a single value. Since constants and random variables are the same kind of object, every operator<br>in the language maps distributions to distributions.
A name always refers to one fixed node, the same way X is the same X across a whole page of math.<br>So X + X is 2X and X - X is exactly 0,. If you want variable independence you<br>write separate draws, ie, using ~ multiple times, or ~[N] to draw N independent variables into a vector.
X ~ unif_int(1, 6)<br>Y ~ unif_int(1, 6)<br>X + Y # two independent dice, a real 2d6 distribution<br>Nothing runs until you ask for some results, for example, P(X + Y , at that moment it forces the runtime to<br>run millions of simulations (across all cores, if available) and return an estimate with a standard error attached.
Bday = unif_int(1, 365)<br>days ~[23] Bday # 23 people in a room<br>P(has_duplicates(days)) # the birthday paradox, about 0.507<br>This is much easier to watch than to describe, so I built some cool demos!
Every value is a distribution
A = 5D1 ~ unif_int(1, 6)D2 ~ unif_int(1, 6)S = A + D1 + D2E(S) draws 0 A ≈ —
Figure 1. The same histogram through four steps: a constant is a single spike, the tilde spreads it into a die, adding two dice curves it toward a bell, and a query reads the mean back.<br>A number is a distribution<br>A = 5 looks like a plain constant, and it is, but Noise<br>sees it as a probability distribution where every draw lands on 5. Statisticians call this a<br>Dirac delta, a single infinitely-thin spike.
The tilde spreads it out<br>D1 ~ unif_int(1, 6) binds a fair die, a discrete<br>uniform where all six faces are equally likely. The spike fans out into six flat bars, so<br>D1 is now uncertain, but you still write it like<br>any other variable.
Join them and a bell appears<br>Add the constant and two independent dice with S = A + D1 +<br>D2. The flat shapes convolve into a triangle peaked at 12, already curving<br>toward a bell, and if you join a few more they sharpen into a true Gaussian. That's the<br>central limit theorem showing up for free!
A query collapses millions of draws<br>Nothing runs until you ask. E(S), the expected<br>value, fires a Monte Carlo pass that averages millions of rolls into one number, and by<br>the law of large numbers the running mean settles on 12. You<br>wrote a few lines of math, and an expert-level kernel ran underneath.
Why it sat for nine years
The design was never the hard part, because a parser and a tree-walking interpreter for this language<br>is a weekend of work. The problem was everything else, writing a efficient Monte Carlo runtime, instead of a naive interpreter, conditional bayesian inference, and more.
Current version is a compiler, a JIT (using the amazing Cranelift), a WASM backend, and a pile of careful numerical<br>code, so for a cute-weekend project it stayed permanently out of reach.
Building the ambitious version with an agent
At my day job and side projects, I am experimenting with the boundaries of what today’s AI agents can do. For example, I am also porting a game I built 15 years ago for iOs, in archaic Objective-C to a modern game engine (with relative success).
With NoiseLand, I realized, AI is great at building the JIT parts, the runtime parts, the numerical parts, but it sucks at coming up with good language design ideas, many times overriding existing language features for different purposes, or coming with with different syntax for non-orthogonal features.
Figure 2. a field of Monte Carlo samples settling under a density curve, drawn live by an inline GLSL shader embedded in this article.<br>One IR, three backends
Under the hood, ~ and the distribution constructors build an append-only DAG called the RvGraph. This graph is the single source of truth,<br>which later are converted into three different code paths:
a columnar batch interpreter that works everywhere and acts as the correctness oracle;
a Cranelift JIT that fuses a whole expression into one native kernel;
a WASM emitter that does the same for the browser.
fallback
fallback
X ~ unif(1, 6)
RvGraph
batch interpreter
Cranelift JIT
WASM emitter
One shared module defines what the graph...