What to read
- The Name in the Bracket: a book about what notation hides, and what happens when you refuse to let it.
- Paper: compact language-design argument.
- Thesis: compiler and runtime details.
A source language for indexed tensor programs, recurrence, and local derivatives.
Most tensor code knows the shape of every array and the role of no axis. Einlang keeps both on the page: named axes, explicit reductions, recurrent dependencies, and derivative requests that live beside the definitions they differentiate.
What to read
let x = 1.0;
let y = x * x + 3.0 * x;
let dy_dx = @y / @x;
print(dy_dx);
Too often, tensor programs disappear into helper calls, layer wrappers, and gradient machinery. Einlang keeps the axes, reductions, and derivatives on the page so the source still reads like the idea behind it.
You can see the axes
Indices and reductions are written directly instead of being hidden in strings or helper calls.
You can see the derivative
Gradient expressions live beside the original definitions, not in a separate autodiff API.
You can keep one notation
The same style carries from simple algebra to recurrences, numerics, and larger models.
The payoff
Programs get easier to inspect, easier to explain, and easier to trust.
This section is about syntax, not slogans. Each example shows one language feature in a more typical style and in Einlang, so you can see what the syntax keeps on the page.
Einstein notation
Indices and reductions are written directly instead of being hidden in a string or helper call.
NumPy / JAX
y = np.einsum("bi,ci->bc", x, W) + bias
Einlang
let y[b, c] = sum[i](x[b, i] * W[c, i]) + bias[c];
Where clauses
Index relations stay attached to the expression instead of being managed as loop bookkeeping.
Python loops
for oh in range(H_out):
for ow in range(W_out):
out[oh, ow] = sum(
inp[oh + kh, ow + kw] * kernel[kh, kw]
for kh in range(KH)
for kw in range(KW)
)
Einlang
let out[oh, ow] = sum[kh, kw](
input[ih, iw] * kernel[kh, kw]
) where ih = oh + kh, iw = ow + kw;
Autodiff syntax
The derivative is part of the program text, not a separate API wrapped around it.
JAX / framework style
def loss_fn(W):
logits = x @ W.T + bias
probs = jax.nn.softmax(logits)
return -(target * jnp.log(probs)).sum()
dloss_dW = jax.grad(loss_fn)(W)
Einlang
let logits[b, c] = sum[i](x[b, i] * W[c, i]) + bias[c];
let probs[b, c] = exp(logits[b, c]) / sum[k](exp(logits[b, k]));
let loss = -sum[b, c](target[b, c] * log(probs[b, c]));
let dloss_dW = @loss / @W;
Fibonacci recurrence
The recurrence uses the same tested form as the repo examples: base cases first, then the recursive rule.
Python loop
fib = np.zeros(11, dtype=int)
fib[0] = 1
fib[1] = 1
for n in range(2, 11):
fib[n] = fib[n - 1] + fib[n - 2]
Einlang
let fib[0] = 1;
let fib[1] = 1;
let fib[n in 2..11] = fib[n-1] + fib[n-2];
Comprehensions and ranges
Generated arrays stay as expressions, and ranges are part of the syntax.
Python
squares = [i * i for i in range(1, 10)]
Einlang
let squares = [i * i | i in 1..10];
Block expressions
Multiple statements can still produce a value, so setup code stays inside the expression that uses it.
Python
tmp = x + y
if tmp > 0:
result = tmp * scale
else:
result = 0
Einlang
let result = {
let tmp = x + y;
if tmp > 0 { tmp * scale } else { 0 }
};
Each document answers a different question: how to learn the notation, what the language-design argument is, how the implementation works, or how to run the code.
Book
Notation determines what you can notice. Sixteen chapters tracing one idea — the coordinate audit — from a Tuesday bug through gradients, recurrence, attention, and dynamic routing, to the principle that organizes them all.
Paper
The compact research argument for keeping indexed definitions, recurrence, and derivative requests in one source language.
Thesis
The fuller implementation writeup, including frontend identity, IR passes, recurrence analysis, autodiff lowering, runtimes, and tests.
Repository
Use the repository for installation, commands, examples, and contribution pointers.
The project is still experimental, but its claims are attached to an implementation: parser and IR passes, executable examples, tests, and generated research artifacts.
Source facts survive lowering
The compiler keeps axes, ranges, recurrence dependencies, and derivative requests available until the pass that consumes each fact.
Examples cover the surface
The repository includes small checks, recurrence suites, optimization examples, and model-shaped programs that stress the same notation.
Dimensions are explicit
The public book focuses on one claim across sixteen chapters: named coordinates state tensor intent where shape-only code leaves it implicit.
Limits are documented
Current limits are part of the public story rather than hidden behind a polished demo.
From here, choose the document that matches your intent. Runnable commands live with the repository docs, where they can stay close to the code.