Authoritative source: Welcome to tulam

Welcome to tulam

tulam is an experimental high-level programming language with an unusually wide ambition: make very expressive types, practical application programming, native performance, and several host platforms belong to one coherent language.

This guide begins with ordinary programs and introduces the deeper ideas only when they become useful. You do not need to know type theory, category theory, Haskell, or compiler construction to begin.

Why another language?

Programming languages often make us choose early:

tulam asks whether these choices can be postponed—or sometimes removed.

The goal is a language that is:

In deliberately over-ambitious shorthand, the dream is “one language to rule them all.” No existing language has completed this exact combination. That is not evidence that the attempt is pointless; it is evidence that the design has to be explicit, testable, and honest about what works today.

One language, not several dialects

Multi-target compilation can easily become several vaguely related languages sharing a parser. tulam takes a stricter approach:

Tulam source
    ↓
strict checking and typed elaboration
    ↓
one closed, verified, optimized RuntimeCore program
    ↓
target provider
    ├── LLVM native       available today
    ├── .NET              planned
    ├── JavaScript        planned
    └── further targets   future providers

A provider may choose an efficient representation, map classes to a host object model, call platform APIs, or use target-specific instructions. It may not reinterpret the source language or quietly skip its static guarantees. This is what makes “the same language on different targets” a technical contract rather than a slogan.

Interoperability follows the same principle. Foreign nullability, exceptions, mutation, asynchronous behavior, and ownership must be represented by checked types, effects, or boundary declarations. Platform convenience should not become invisible unsafety.

Expressive types, explained gently

Most languages let a function’s result value depend on an argument value. tulam also lets its result type depend on an argument:

function replicate[a:Type](count:Nat, item:a) : Vec(a, count) = ...;

The result records its length. A caller that supplies count receives a vector whose type contains that same value. This is a dependent function, traditionally called a Pi type.

Data can be dependent too:

type SizedVector(a:Type) =
    size:Nat * values:Vec(a, size);

The type of values refers to the preceding size field. This is a dependent product, traditionally called a Sigma type. You will learn both from concrete examples before the guide asks you to reason about their formal names.

The aim is not to turn every program into a proof. Ordinary code should remain ordinary. Richer types are tools for the places where a useful fact—dimensions, protocol state, available effects, a representation, a target capability—can prevent an entire class of mistakes.

The small core: lambdas and telescopes

Two ideas organize tulam’s core.

A lambda is a function: it binds inputs and produces a result. Named functions, anonymous functions, methods, and many higher-level constructs eventually share this machinery.

A telescope is an ordered n-tuple of fields in which each field may depend on earlier fields. Ordinary tuples, records, constructor payloads, function parameters, argument lists, dependent products, evidence packages, and class fields all use this one idea.

For example:

{3, True, "three"}

is one flat three-field tuple. It is not compiler-generated shorthand for a pair containing another pair. Explicit nesting remains explicit:

{3, {True, "three"}}

This distinction persists through checking and compilation. It gives the language a uniform semantic model while leaving target providers free to unbox or otherwise optimize a representation without changing its meaning.

Performance without a second language

tulam’s performance goal is not to bolt a separate “kernel language” onto an otherwise high-level system. The compiler first produces one checked executable core. Optimization and target lowering happen behind that boundary.

For numerical work this permits, over time:

One example already exposed by the native toolchain is floating-point contraction. The default --fp-contract=off preserves separate multiply and add operations. --fp-contract=fast permits contraction into a fused operation where supported. This is an artifact-wide, visible choice—not an undocumented change made by a backend.

“Fast” must always mean “fast within the selected semantic contract.”

What works today

LLVM native is the sole reference implementation and the current execution backend. It is the target used for routine correctness, conformance, and performance testing.

The current implementation has substantial support for ordinary functional programming, algebraic data, Pi and Sigma types, structures and evidence, classes, effects, representations, projects, and native compilation. Some specified areas remain incomplete, notably:

The exact list changes as development proceeds. This guide marks incomplete features where they appear, while the Implementation Plan remains the authoritative status record. The Language Reference defines the language, including specified features that may still have an implementation gap.

How to use this guide

The first five chapters form a quick start:

  1. this chapter explains the purpose and shape of the language;
  2. Installing tulam prepares the compiler and editor;
  3. Your first program checks and runs one source file;
  4. Check, run, build, and test introduces the normal project workflow; and
  5. A guided tour combines several language features in one small program.

After that, the guide proceeds from everyday expressions and data toward the type system, abstraction, effects, objects, targets, and larger projects. The complete table of contents offers alternative entry points.

Examples use the canonical surface language. A status callout means “this is part of the specified language, but current execution support has a named limit.” It never means “use this different syntax for now.”

A useful mindset

You can begin by treating tulam as a strict functional language with familiar data declarations, functions, and pattern matching. The deeper machinery will still be there when a problem needs it.

The most productive question is not “How much type theory must I learn first?” It is “What fact would make this program easier to use correctly?” tulam’s type system gives you room to answer that question more precisely as your program grows.

Next: Installing tulam and editor support.