Explicit by construction
Strong static types, no type inference. Free-standing functions, no methods, function pointers, or closures. No recursion. Named call arguments show what each value means; explicit operations show what each function does.
An experimental language for people & machines
A human-readable intermediate representation for AI-generated programs. Precise enough for a language model to write. Explicit enough for a developer to audit.
Compile time ↓ Run time ↓
A direction, not a promise of zero. Less waiting. Less overhead. More useful work.
01 / Read what runs
Not an opaque intermediate representation. Not shorthand that hides a second language. A compiled Lisp with explicit types, named call arguments, and visible control flow.
Builtins wear #. Invoke generators with #generate; file imports use explicit #alias declarations. Even arithmetic states its type and overflow behavior.
// A function, not a method.
(#fn add ((left #u64) (right #u64)) #u64
(#return (#u64::add-wrap left right)))
(#fn main () #u64
(#let answer #u64
(#call add ((left 40u64) (right 2u64))))
(#return answer))
02 / Built for generation. Designed for inspection.
Strong static types, no type inference. Free-standing functions, no methods, function pointers, or closures. No recursion. Named call arguments show what each value means; explicit operations show what each function does.
Full monomorphization through code generation, rather than user-facing generic types. Pure generators produce concrete Lim definitions. Their output is source you can read, search, and review.
(#generate #optional ((type #u64) (name MaybeU64)))
Generated source lives in .lim, with call-site provenance. Hash-based caches reuse unchanged generator inputs and dependencies. Inspect the actual implementation, not just a macro invocation.
03 / Names you can follow
Global declarations live in a single namespace. There are no nested namespaces or method lookup rules to reconstruct before following a call. VecU64::sort is a function name, not a method selected through a receiver.
A name such as Work::poll identifies a free-standing function. Choice.Ready identifies an enum variant. Imports explicitly name their source file and declared symbol.
Search a function or type name to follow its definition and uses. Free-standing functions and no shadowing keep names from silently changing meaning. You can trace the code with a text search, without first understanding a dispatch hierarchy.
Generated definitions are searchable Lim files in .lim, too. Their headers record the invoking files and lines, so you can follow an implementation back to the code that requested it.
The entire #-prefixed identifier space is reserved for the language. Keywords, builtin types, and operations are visibly marked: #fn, #u64, #return. Invoke language and standard-library generators with forms such as (#generate #optional ...); invoke your own with (#generate make-record ...).
This supports backward-compatible keyword additions: a future #feature does not turn your existing feature identifier into a keyword. The prefix prevents name collisions; it is not a blanket guarantee against every syntax or semantic change.
04 / Explicit does not mean unchecked
The compiler follows ownership and borrowing across the program—not just the function in front of you. Explicit source and static checks work together: auditability is not a substitute for safety.
05 / Time is part of the design
A dependency-free Rust compiler with its own native instruction encoding and ELF linking. No external assembler or linker in the normal executable build path.
Cached generation avoids repeating unchanged work. Reachability-based emission keeps unused functions out of executable builds. Concrete implementations keep runtime dispatch visible.
Speed is an engineering target, not a universal timing guarantee. Measure your workload with the compiler benchmark harness.
Start with the source
From a checkout of the Lim repository, compile the example above:
nix develop
cargo build --release
./target/release/lim docs/answer.lim -o answer
./answer
# Exit status: 42
Lim is experimental and unreleased. Its syntax and semantics may still change; reserved keyword prefixes are designed to protect user names as the language grows. This is a foundation for explicit, auditable systems—not a finished ecosystem.