Интерпретатор Lisp в типовой системе Rust

GitHub-проект playX18 демонстрирует, как использовать типовую систему Rust для выполнения Lisp-кода на этапе компиляции. Каждый символ вручную объявляется через макрос defkey!(), числа хранятся в диапазоне 0-8192 (можно расширить, если увеличить стек). Интерпретатор поддерживает определение функций, рекурсию, лямбды и даже call/ec для управления потоком выполнения.
Например, факториал вычисляется как типовая аннотация, где компилятор Rust проверяет, что (fac 5) действительно даёт 120. Проект - скорее демонстрация возможностей типовой системы Rust, чем практический язык: нет макросов, eval, отрицательных чисел и полного набора функций стандартного Lisp.
Ключевые факты
- Весь Lisp-интерпретатор работает в типовой системе Rust, код вычисляется на этапе компиляции
- Поддерживает определение функций, рекурсию, лямбды, глобальные и локальные переменные, вызовы через apply
- Реализован call/ec для управления потоком выполнения с помощью escape-continuations
- Ограничения: числа только от 0 до 8192, нет макросов и eval, нет поддержки отрицательных чисел
- Результаты вычислений проверяются типовой системой - например, assert_same проверяет, что факториал 5 равен 120
Почему это важно
Проект показывает, что типовые системы современных языков программирования намного более выразительны, чем казалось раньше. Используя механизм associated types и трейтов Rust, можно реализовать полноценный интерпретатор Lisp, выполняя логику во время компиляции. Это не просто забавная демонстрация - это открывает возможности для мета-программирования и проверки инвариантов кода на этапе компиляции.
Кому это важно
Разработчикам на Rust, которые интересуются расширенными возможностями типовой системы и генеративным программированием. Исследователям, работающим над языковыми расширениями и компиляторами. Авторам библиотек, которые ищут способы переместить вычисления на этап компиляции для производительности или безопасности.
Как это применить
На практике этот подход полезен для встроенных DSL (domain-specific languages) в Rust, которые вычисляются на этапе компиляции. Можно использовать типовую систему для описания конфигураций, которые должны быть полностью известны на этапе компиляции, или для символических вычислений. Однако для чего-либо серьёзнее образовательной цели стоит рассмотреть proc-macros как более практичную альтернативу.
Можно ли доверять
Это любительский проект, автор честно указывает ограничения и не претендует на полноту реализации. Код работает для демонстрационных примеров вроде факториала и call/ec, но не тестировался на более сложных программах. Проект интересен как proof-of-concept, но использовать его как основу для продакшена не стоит.
Риски и подводные камни
Времена компиляции Rust резко возрастут при использовании этого подхода для нетривиального кода - типовая система не оптимизирована для итеративных вычислений. Ограничение на 8192 числа и отсутствие отрицательных чисел делают его непригодным даже для средних программ. Сообщения об ошибках компилятора Rust в таком контексте будут нечитаемы.