AffineScript is a programming language that combines:
- Affine Types — Rust-style ownership without a garbage collector
- Dependent Types — Types that depend on values for compile-time guarantees
- Row Polymorphism — Extensible records with type-safe field access
- Extensible Effects — User-defined, trackable side effects
It compiles to WebAssembly for efficient, portable execution.
fn processFile(path: ref String) -> Result[String, IOError] / IO {
let file = open(path)?; // file is owned
let content = read(ref file)?; // borrow file
close(file)?; // consume file
Ok(content)
}
total fn head[n: Nat, T](v: Vec[n + 1, T]) -> T / Pure {
match v {
Cons(h, _) => h // Can't call on empty vec - type prevents it
}
}
fn greet[..r](person: {name: String, ..r}) -> String / Pure {
"Hello, " ++ person.name // Works on any record with 'name'
}
greet({name: "Alice", age: 30}) // OK
greet({name: "Bob", role: "Admin"}) // Also OK
effect State[S] {
fn get() -> S;
fn put(s: S);
}
fn counter() -> Int / State[Int] {
let n = get();
put(n + 1);
n
}
Requires OCaml 5.1+ and opam:
git clone https://github.com/hyperpolymath/affinescript.git
cd affinescript
opam install . --deps-only
dune build# Lex a file
affinescript lex example.as
# Parse a file
affinescript parse example.as
# Type check
affinescript check example.as
# Compile to WebAssembly
affinescript compile example.as -o output.wasmAffineScript is under active development. Current status:
| Component | Status |
|---|---|
| Lexer | In Progress |
| Parser | Planned |
| Type Checker | Planned |
| Borrow Checker | Planned |
| Effect System | Planned |
| WASM Backend | Planned |
Contributions are welcome! Please read CONTRIBUTING.md before submitting PRs.
MIT License. See LICENSE for details.
- Rust — Inspiration for affine types
- Idris — Inspiration for dependent types
- Koka — Inspiration for effect system
- PureScript — Inspiration for row polymorphism