- and: fix base case for 2 args (was double-wrapping in if) - or: simplify to direct if without let/gensym - when: remove nil else branch, validate args.len >= 2 - cond: recursive expansion with cond in else branch - as->: swap arg order to match Clojure (init, name, body) - some->: use nil? check instead of truthy check
Clojure/Nim
A Clojure dialect that compiles to Nim → C → native binaries.
| JVM Clojure | Clojure/Nim | |
|---|---|---|
| JVM required | ❌ | ✅ No |
| GraalVM/native-image | ❌ | ✅ No |
| Google Closure Compiler | ❌ | ✅ No |
| Java stdlib dependency | ❌ | ✅ No |
| Startup time | ❌ Slow (JVM warmup) | ✅ Instant |
| Binary size | ❌ 50MB+ | ✅ < 1MB |
Quick Start
git clone https://gitlab.com/balvatar/lisp-nim.git
cd lisp-nim
make build
make check
./cljnim run examples/hello.clj
Documentation
- English — Getting started, architecture, AI integration, API reference
- Български — Първи стъпки, архитектура, AI интеграция, API справочник
- Clojure Test Suite — Cross-dialect compliance testing with the jank-lang/clojure-test-suite
What is this?
Clojure/Nim is an AI-first Clojure implementation targeting the Nim ecosystem. It compiles Clojure source directly to Nim, then to C, and finally to a native binary.
Unlike every other Clojure dialect, this project has zero dependency on the Java ecosystem:
| Dialect | JVM? | Java Ecosystem Dependency |
|---|---|---|
| Clojure (JVM) | ✅ Required | Full — runs on JVM, uses Java stdlib |
| ClojureScript | ❌ | Heavy — Google Closure Compiler, JS ecosystem |
| Babashka | ❌ | Medium — GraalVM native-image, still JVM-based |
| Clojure/Nim | ❌ | None — completely standalone |
Why?
- Native Performance — No JVM warmup, no GC pauses, C-speed execution
- Tiny Binaries — Single-file executables, often under 1MB
- Nim Ecosystem — Direct access to Nim and C libraries via FFI
- AI-Native — JSON REPL, batch evaluation, AI-assisted error messages and code generation
- True Independence — No JVM, no GraalVM, no Java stdlib, no Google Closure
What Makes This Unique?
1. Completely Independent from Java
This is the only Clojure dialect that does not depend on any part of the Java ecosystem — not the JVM, not GraalVM, not the Java standard library, and not Google Closure Compiler. The entire toolchain is self-contained: Clojure source → Nim source → C source → native binary.
2. Native HAMT Persistent Data Structures
Built from scratch in Nim:
- Persistent Vector — Hash Array Mapped Trie with 32-way branching and structural sharing
- Persistent Map — HAMT-based immutable hash map, O(log₃₂ n) operations
- Persistent Set — Backed by HAMT map
- Transients — Batch mutations with
conj!,assoc!,persistent!
No Java PersistentVector.java or IPersistentMap interfaces — our own implementation optimized for Nim's memory model and ORC garbage collector.
3. Multiple Compilation Targets from One Codebase
The same Clojure code compiles to:
| Target | Status | Use Case |
|---|---|---|
| Native binary | ✅ Ready | CLI tools, system programming, servers |
| Native shared library (.so/.dll/.dylib) | ✅ Ready | Embed Clojure in Python/Rust/Go/C via FFI |
| WASM | ✅ Ready | Browser, serverless, edge computing |
| JavaScript | ✅ Ready | Frontend, Node.js without 50MB JVM |
4. AOT Compiler — Not an Interpreter
Full ahead-of-time compilation like ClojureScript, but without the JavaScript/Google Closure dependency:
- Fast runtime execution at C speed
- Small binary sizes with no interpreter overhead
- REPL uses a hybrid model: tree-walking interpreter for fast feedback (<1ms eval), AOT compilation for production builds
5. Nim/C Interop Instead of Java Interop
Direct FFI to the Nim and C ecosystem:
(nim/math/sin x)
(nim/strutils/toUpper s)
Nim modules are auto-imported. No JNI, no JVM bridging, no Java interop overhead.
6. AI-Native Tooling Built-In
- AI-assisted errors — DeepSeek/MiMo explain compiler errors
- AI code generation —
(ai/generate "quicksort")in REPL - AI optimization hints —
(ai/optimize code)suggests algorithm improvements - AI debugging —
(ai/debug expr)analyzes runtime behavior - JSON REPL protocol — Structured I/O designed for AI agents and IDE integration
7. Concurrency Without the JVM
- Atoms — Compare-and-swap semantics
- Agents — Async state updates with
send/await - core.async channels —
chan,>!,<!,gomacros — CSP-style concurrency without JVM threads
Key Features
| Feature | Status |
|---|---|
| Compiler (Clojure → Nim → C → native) | ✅ |
| REPL with JSON protocol | ✅ |
Macro system (defmacro, syntax-quote, ->, ->>) |
✅ |
| Persistent data structures (HAMT vector/map/set) | ✅ |
| Transients for batch mutations | ✅ |
| Atoms, Agents, Channels | ✅ |
loop/recur |
✅ |
try/catch/finally |
✅ |
Namespace system (ns, :require) |
✅ |
| Dependency resolution (deps.edn, Git deps) | ✅ |
| Nim/C FFI interop | ✅ |
| AI integration (DeepSeek, OpenAI, MiMo) | ✅ |
| Cross-compilation targets (JS, WASM, shared libs) | ✅ |
| Self-hosted REPL with tree-walking interpreter | ✅ |
| 276+ tests | ✅ |
Example
;; examples/math.clj
(defn factorial [n]
(if (= n 0)
1
(* n (factorial (- n 1)))))
(println (factorial 5)) ;; => 120
$ ./cljnim run examples/math.clj
120
AI-Powered Development
export DEEPSEEK_API_KEY="sk-..."
./cljnim ai "function that sums a list using loop/recur"
See docs/en/03-ai-integration.md for details.
License
MIT — see LICENSE