(tulam)

The most expressive type system.
Every backend. Native performance.

Dependent types, algebraic effects, and a compiler targeting JS, .NET, and LLVM — matches C++ on real benchmarks, up to 11× faster on pure work.

Get Started See Examples
hello.tl
// Sum types with pattern matching
type Maybe(a:Type) = Nothing + Just * val:a;

// Algebraic structures (typeclasses)
algebra Monoid(a:Type) extends Semigroup(a) = {
    value empty : a;
};

// Functions with dependent types
function map(f: a -> b, xs: List(a)) : List(b) = match xs
    | Nil         -> Nil
    | Cons(h, t)  -> Cons(f(h), map(f, t));

Why tulam?

A language designed from first principles, where the type system is the language.

λ

Two Primitives

The entire type system — sum types, records, classes, effects — derives from tuples and lambdas. No hidden machinery. Every abstraction compiles down cleanly.

Categorical Vocabulary

algebra equips one type. morphism relates two or more. extends builds hierarchies. Laws are compiler-verified propositions, not comments. The compiler derives compositions automatically.

Σ

Sigma Types

Full dependent pairs and existentials with flat runtime layout. O(1) field access, zero pointer chasing — maps directly to .NET objects, JS objects, and C structs.

Π

Pi Types & Universes

Dependent functions (x:A) → B(x), a cumulative universe hierarchy, and type-level computation that reuses the same evaluator as values. One language, not two.

Laws as Code

Algebras declare equational laws with ===. Not comments — the compiler carries them forward for rewrite-rule optimization and property test generation.

Composable Effects

Effects are row-polymorphic: no monad transformers, no lift. Swap handlers per call-site — mock IO for tests, change concurrency backends, sandbox modules.

Repr System

Bidirectional representation mappings between user types and machine types. expr as Type inserts conversions automatically — direction resolved from the repr map.

First-Class Classes

OOP classes with 1-1 codegen mapping. class compiles to an actual class on every target — .NET, JS, C++. Single inheritance, abstract, sealed, override, final.

Multi-Target Interop

Compile to JS, .NET, or native via LLVM. Algebra-based interop: write a pure contract, provide target-qualified instances. The compiler selects and inlines per build target.

By Example

tulam combines the elegance of ML with the rigor of type theory.

Algebras & Morphisms

An algebra equips one type with operations. A morphism relates two types directionally. Laws use === — they're not comments, they're compiler-verified propositions used for optimization and testing.

categorical.tl
algebra Monoid(a:Type) extends Semigroup(a) = {
    value empty : a;
    law left_identity(x:a) =
        combine(empty, x) === x;
};

// Morphisms relate two types
morphism Iso(a:Type, b:Type)
    extends Convertible(a, b) = {
    function unconvert(x:b) : a;
    law roundtrip(x:a) =
        unconvert(convert(x)) === x;
};

Sigma Types & Existentials

Full dependent pairs where later fields depend on earlier values. Existentials hide concrete types behind interfaces. Flat runtime layout — O(1) field access, no nested pairs.

sigma.tl
// Existential: hide the type, keep the interface
type Showable = exists (a:Type).
    val:a * show:a -> String;

// Pi types — return type depends on value
function replicate(n:Nat, x:a) : Vec(a, n) =
    match n
    | Z       -> VNil
    | Succ(k) -> VCons(x, replicate(k, x));

// Unpack existentials
unpack showable as (a, s) in s.show(s.val);

Composable Effect Handlers

Effects compose via row polymorphism — no monad transformer stacks, no lift. Swap handlers at the call site to mock IO, change backends, or sandbox modules. The same code runs pure or effectful.

effects.tl
effect Console = {
    function print(s:String) : Unit;
    function readLine() : String;
};

handler StdConsole : Console = default {
    function print(s) = putStrLn#(s);
    function readLine() = readLine#();
};

// Swap the handler — no code changes needed
greet [Console = TestConsole] ("world");

Repr System & Target Interop

Bidirectional representation mappings between user types and machine types. expr as Type auto-inserts conversions. Target-qualified instances let the compiler select platform-native implementations per build target.

interop.tl
// Map user types to machine types
repr Nat as Int default where {
    function toRepr(n:Nat) : Int = match n
        | Z       -> 0
        | Succ(m) -> 1 + toRepr(m);
};

// Target-qualified instances
target dotnet {
    instance Show(Int) =
        System.Int32.ToString;
};

First-Class OOP

Not an encoding — class compiles to a real class on every target. Single inheritance, abstract, sealed, override, final. Extend .NET/JS/C++ classes transparently from tulam source.

classes.tl
abstract class Shape(color:String) = {
    function area(self:Shape) : Float64;
    function describe(self:Shape) : String
        = "A " ++ self.color ++ " shape";
};

class Circle(radius:Float64)
    extends Shape = {
    override function area(self:Circle)
        : Float64 =
        3.14159 * self.radius * self.radius;
};

Performance

Are We Fast Yet benchmarks — tulam native vs C++ (clang++ -O3 -flto), Haskell (GHC -O2), and JavaScript (Node.js). Geometric mean puts tulam within 10% of C++, faster than GHC overall, and winning on 6 of 9 benchmarks vs C++.

Benchmark C++ Haskell Node.js tulam native vs C++
List 8 µs 6 µs 50 µs 11 µs 1.3x
Queens 7 µs 3 µs 75 µs 6 µs 0.8x
Permute 11 µs 36 µs 79 µs 1 µs 0.1x
Sieve 9 µs 27 µs 100 µs 9 µs 1.0x
Towers 14 µs 46 µs 103 µs 50 µs 3.5x
NBody 8.8 ms 23.6 ms 12.0 ms 7.8 ms 0.9x
Bounce 5 µs 18 µs 159 µs 7 µs 1.4x
Storage 196 µs 63 µs 203 µs 112 µs 0.6x
Mandelbrot 19.4 ms 9.4 ms 20.0 ms 12.4 ms 0.6x
Geometric mean 1.0x 1.9x 8.6x 1.1x

Faster than C++  —  Lower is better. Ratios show time relative to C++. Apple Silicon (arm64-darwin), measured 2026-04-23. Benchmarks from Are We Fast Yet — objects, closures, arrays, no micro-tricks.

Current Status

tulam is under active development. Here's where things stand.

Language

  • Surface syntax finalized
  • Parser complete
  • Bidirectional type checker
  • Module system with caching
  • Standard library (13 modules)
  • 1086 tests passing

Backends

  • Bytecode interpreter
  • LLVM native compilation
  • JavaScript codegen
  • .NET codegen

Coming Next

  • Full HKT support
  • Effect handler codegen
  • JS & .NET targets
  • Package manager

Get Started

tulam is built with Haskell Stack. Clone, build, and start the REPL in under a minute.

terminal
# Clone the repository
$ git clone https://github.com/aantich/tulam.git
$ cd tulam

# Build with Stack
$ stack build

# Start the REPL (loads standard library automatically)
$ stack exec tulam

tulam> 1 + 2
3

tulam> map(fn(x) = x * 2, Cons(1, Cons(2, Cons(3, Nil))))
Cons(2, Cons(4, Cons(6, Nil)))