One high-level language for mathematics, applications, objects, and heterogeneous execution.
Proper Pi and Sigma types, algebraic evidence, first-class classes, deep effects, explicit call-by-need, and target-aware optimization without call-site ceremony.
// Library authors state optional placement once. value bulkCompute : TargetPolicy = prefer(capability(ParallelBulk), current); function sumOfSquares(xs:c(a)) : a requires Field(a), Bulk(c) on bulkCompute = fold((+), zero, fmap(fn(x) = x * x, xs)); // Application code remains an ordinary call. value total = sumOfSquares(samples);
A single semantic language, with cost and platform boundaries explicit where they matter.
Dependent application substitutes the accepted argument term. Universes are cumulative through checked lifting, not indiscriminate unification.
Dependent pairs, flat telescopes, existential abstraction, GADTs, and first-class evidence share one scoped representation.
structure, algebra, and morphism elaborate to coherent evidence. Composition is explicit rather than guessed globally.
A law is a typed proposition with declared, tested, proven, trusted, or compiler-validated status. Declaration alone never creates Refl.
Scope-safe semantic codes support computed data and algebra-owned derivation. Runtime type identity stays separate from provider layout.
Nominal classes, inheritance, dynamic dispatch, and checked subtyping are language concepts. Providers map them to native class models when contracts permit.
Row-polymorphic effects use deep handlers and scoped resumptions. Affine is the default; multi-shot control is requested explicitly.
Strict evaluation is the default. Lazy(a), ~expr, and force provide memoized call-by-need with sharing and black-hole detection.
repr controls semantic-to-storage conversion. Cross-target residence and transfer remain separate, typed operations.
Native code, managed runtimes, accelerators, processes, containers, and remote workers use one profile, capability, policy, and fallback model.
These examples follow the normative Language Reference. Some specified constructs remain implementation work.
Telescopes let later fields depend on earlier values. Existentials reuse Sigma introduction and scoped elimination rather than adding dynamic casts.
type SizedVector(a:Type) = size:Nat * values:Vec(a, size); type Showable = exists (a:Type). { value:a, display:a -> String }; value item : Showable = { value = 42, display = showInt }; unpack item as (a, x) in x.display(x.value)
Evidence is selected coherently and remains first-class after elaboration. Laws document algebraic intent, while pure intrinsic values let providers supply typed constants without changing the algebra.
algebra Monoid(a:Type) extends Semigroup(a) = { value empty : a; law leftIdentity(x:a) = combine(empty, x) === x; law rightIdentity(x:a) = combine(x, empty) === x }; instance Monoid(PackedPolynomial) = { function combine(x, y) = intrinsic; value empty = intrinsic };
Effects appear in function types. Handlers are deep, and resume is a scoped function binding whose multiplicity follows the effect contract.
effect Choice requires Resumption(Many) = { function choose[a:Type](options:List(a)) : a }; handler FirstChoice : Choice = { function choose[a:Type](options:List(a)) = resume(head(options)) }; handle choose(values) with FirstChoice
Typed semantic codes can generate data without exposing target layout. Derivation then produces ordinary checked evidence with inferred field requirements.
type Source(a:Type) = None + Some * item:a; function schema(code:DataCode(Unit, Z)) : DataCode(Unit, Z) = renameDataType(code, "Generated"); type Generated(a:Type) = schema(dataCode(reflect(Source(a)))); instance Eq(Generated(a)) = derive;
Placement metadata belongs to declarations. Providers refine canonical functions inside target blocks; callers do not write execution blocks or processor names.
function matrixMultiply(a:Matrix, b:Matrix) : Matrix on compute = portableMatrixMultiply(a, b); target FastAccelerator { function matrixMultiply(a, b) = intrinsic; }; value result = matrixMultiply(left, right);
Class declarations are canonical across targets. Subtyping elaborates explicit core coercions; target providers choose native or portable object layouts.
class Animal(name:String) = { function describe(self:Self) : String = self.name }; class Dog(breed:String) extends Animal("unknown") = { override function describe(self:Self) : String = self.breed }; value dog = Dog.new("Collie");
Tulam's balanced and throughput memory profiles compared with C++, Node.js, and GHC across all nine Are We Fast Yet workloads.
| Benchmark | Tulam balanced | Tulam throughput | C++ | Node.js | Haskell |
|---|---|---|---|---|---|
| Sieve | 21.0 µs | 25.0 µs | 21.9 µs | 51.0 µs | 75.6 µs |
| Queens | 22.0 µs | 22.0 µs | 17.1 µs | 95.9 µs | 9.421 µs |
| Bounce | 23.0 µs | 23.0 µs | 13.1 µs | 40.1 µs | 685.2 µs |
| Permute | 24.0 µs | 21.0 µs | 29.5 µs | 95.8 µs | 121.5 µs |
| Storage | 178.0 µs | 198.0 µs | 762.0 µs | 263.1 µs | 185.7 µs |
| Towers | 237.0 µs | 327.0 µs | 42.5 µs | 136.9 µs | 145.1 µs |
| List | 30.0 µs | 37.0 µs | 24.7 µs | 43.9 µs | 185.5 µs |
| Mandelbrot | 63.2 ms | 70.3 ms | 62.5 ms | 60.2 ms | 81.6 ms |
| NBody | 20.5 ms | 22.3 ms | 41.6 ms | 53.5 ms | 95.3 ms |
| Geometric mean vs C++ | 1.04x | 1.14x | 1.00x | 1.90x | 2.70x |
Local arm64 measurements from one five-backend run on 2026-08-09 using benchmarks/awfy/run_benchmarks.sh. Every backend uses one warm-up plus the median of five independent process runs, with compilation and startup excluded. Small workloads use 1,000 self-timed iterations, Storage uses 100, and NBody/Mandelbrot use 3. Tulam uses --fp-contract=off; C++ uses Apple clang 17 C++17 -O3, Node.js is 23.2.0, and Haskell uses GHC 9.10.3 -O2. Haskell repetitions are forced through runtime inputs; fractional microseconds are preserved. Lower is better.
The design is normative; implementation support is incremental. Snapshot: 2026-08-09.
Build with Haskell Stack, then check, build, or run a typed Tulam project or single source file through LLVM native.
# Clone and build $ git clone https://github.com/aantich/tulam.git $ cd tulam $ stack build # Open the persistent compiled shell (LLVM ORC, with isolated AOT startup fallback) $ stack exec tulam # In a directory containing tulam.project.tl $ stack exec tulam -- check $ stack exec tulam -- run $ stack exec tulam -- test $ stack exec tulam -- project graph # Run compiler, project, and language checks $ stack test $ ./tests/run_conformance.sh $ ./tests/run_projects.sh $ ./tests/run_repl.sh # Native build: preserve multiply/add rounding boundaries (default) $ stack exec tulam -- build example.tl --backend native --entry main --fp-contract=off # Optionally permit fused multiply-add contraction $ stack exec tulam -- build example.tl --backend native --entry main --fp-contract=fast