Jolt: компилятор Clojure на Chez Scheme, без JVM и сборки
Jolt, новая самостоятельная (self-hosted) реализация Clojure, которая выполняется поверх Scheme, а не JVM: нативно она работает на Chez Scheme, а для запуска в браузере компилируется в JavaScript бэкендом Gambit. По документации проекта, JVM не нужен, отдельный шаг сборки не нужен, и большая часть переносимого кода Clojure выполняется без изменений. Компилятор транслирует код Clojure в промежуточное представление, не зависящее от хост-платформы, затем генерирует код на Scheme и выполняет его; сам компилятор написан на Clojure и компилирует себя.
Команда jolt build заранее (ahead-of-time) компилирует проект, рантайм, стандартную библиотеку, приложение и его зависимости, в единый автономный исполняемый файл: для его запуска не нужны ни Chez, ни JVM, ни исходный код. Установить сам Jolt можно через Homebrew (brew install jolt-lang/jolt/jolt) или скриптом установки для Linux и macOS; есть и вариант без установки, запуск из клонированного репозитория, для которого нужен только Chez Scheme, а стартовый бинарник для самосборки (bootstrap seed) уже лежит в репозитории.
Конкурентность реализована через future, promise, agent и pmap, которые работают на потоках операционной системы поверх общей кучи, с той же семантикой, что и на JVM, а core.async даёт каналы и блоки go. Числовая башня включает точные целые числа и большие числа (bignum), точные дроби ((/ 1 2) даёт 1/2) и числа с плавающей точкой; оператор = учитывает категорию числа, а == сравнивает только значение. Структуры данных, неизменяемые векторы на деревьях с разветвлением 32 (32-way trie), cons-списки и HAMT-реализации map/set с семантикой значений Clojure; временные изменяемые коллекции (transients), это настоящие мутируемые структуры, а не эмуляция.
Из возможностей Clojure на JVM в Jolt работают: ленивые и бесконечные последовательности, трансдьюсеры, деструктуризация, мультиметоды, протоколы и записи (records), метаданные, пространства имён, вычисление кода во время выполнения (runtime eval) и полноценный ридер. Поддерживается разработка с подключением к живому процессу: jolt --nrepl-server сам находит deps.edn, поднимает nREPL-сервер и пишет файл .nrepl-port, к которому подключаются CIDER, Calva или Cursive, переопределённая переменная подхватывается следующим вызовом без перезапуска процесса.
На сайте проекта работает живой терминал: это сам Jolt, скомпилированный в JavaScript бэкендом Gambit и выполняющийся прямо в браузере, в урезанной сборке без модуля регулярных выражений, о чём интерпретатор честно сообщает при попытке им воспользоваться. При этом документация обрывается ровно на месте, где должна начаться конкретика: раздел, обещающий перечислить «подлинные расхождения» (genuine divergences) поведения Jolt и JVM-версии Clojure, в сохранённом тексте не раскрыт, какие именно случаи не совпадают, из материала не видно. Автор или сопровождающий проекта, версия, лицензия и сравнительные замеры производительности с JVM-версией Clojure в тексте тоже не названы.
Ключевые факты
- Jolt выполняет Clojure на Chez Scheme нативно и на Gambit, как JavaScript в браузере, вместо JVM, без JVM и без отдельного шага сборки.
jolt buildзаранее компилирует рантайм, стандартную библиотеку, приложение и зависимости в один автономный исполняемый файл, которому не нужны ни Chez, ни JVM, ни исходники.- Конкурентность (future/promise/agent/pmap, core.async) и числовая башня (точные дроби, bignum) воспроизводят семантику JVM-версии Clojure; коллекции, неизменяемые векторы на деревьях с разветвлением 32, HAMT map/set, настоящие transients.
- Сам компилятор Jolt написан на Clojure и компилирует себя, то есть является самостоятельной (self-hosted) реализацией языка.
- Документация обрывается перед списком конкретных расхождений с JVM-семантикой Clojure; автор, версия, лицензия и замеры производительности в тексте не указаны.
Почему это важно
Clojure долго был неотделим от JVM: холодный старт, тяжёлый рантайм и необходимость ставить Java мешали там, где нужен компактный CLI-инструмент или встраиваемый скрипт. Jolt снимает эту зависимость, та же семантика языка выполняется на Chez Scheme вовсе без JVM, а jolt build даёт один переносимый бинарник. Отдельно показательно, что компилятор Jolt написан на самом Clojure и компилирует сам себя, это говорит о том, что платформа достаточно зрелая, чтобы на ней писать реальный код, а не только тестовые примеры.
Кому это важно
В первую очередь, разработчикам на Clojure, которым нужно распространять CLI-утилиты и сервисы без требования ставить JVM на машину пользователя. Также, тем, кто хочет запускать код на Clojure в браузере: бэкенд на Gambit компилирует его в JavaScript, что и показывает демо-терминал на сайте проекта. И разработчикам, привыкшим к REPL-ориентированной разработке в CIDER, Calva или Cursive, которым Jolt даёт nREPL-сервер с автоопределением deps.edn.
Как это применить
Поставить Jolt можно через Homebrew (brew install jolt-lang/jolt/jolt) или установочным скриптом для Linux и macOS; либо клонировать репозиторий и запускать без сборки, нужен только Chez Scheme, а стартовый бинарник (bootstrap seed) уже в репозитории. Для сборки самостоятельного исполняемого файла проекта используется jolt build -m <namespace> -o <имя>, с флагами --opt для оптимизированной сборки и --dev для неоптимизированной. Для разработки с живой перезагрузкой кода, jolt --nrepl-server, который сам находит deps.edn и пишет файл .nrepl-port для подключения редактора.
Можно ли доверять
Материал, это официальная документация проекта Jolt, набравшая заметный отклик на Hacker News (191 балл и 64 комментария примерно за трое суток), но сам текст не называет ни автора, ни сопровождающего проекта, ни номер версии, ни лицензию, эти данные по сохранённому тексту проверить нельзя. Заявления о совместимости с JVM-семантикой Clojure исходят исключительно от самого проекта: независимых замеров производительности или совместимости в материале нет, а раздел с перечнем реальных расхождений от JVM-поведения в сохранённом тексте обрывается, не начавшись.
Риски и подводные камни
Главный риск, именно та часть документации, которая недоступна: список «подлинных расхождений» с JVM-семантикой Clojure, то есть мест, где код на Jolt поведёт себя иначе, чем на JVM, в сохранённом тексте не раскрыт. Без этого списка нельзя заранее понять, какие библиотеки или паттерны кода перенесутся без переделки. Стоит учитывать и то, что это новый проект без указанной в тексте версии и лицензии, без опубликованных сравнительных замеров производительности и без явного заявления о зрелости API для продакшена.
«Jolt, это самостоятельная (self-hosted) реализация Clojure, которая выполняется поверх Scheme: нативно на Chez, а для JavaScript, через Gambit. JVM не нужен, отдельный шаг сборки не нужен, большая часть переносимого кода Clojure выполняется без изменений.»
— документация проекта Jolt