Автор, разработчик с опытом в телекоммуникациях, задумал NoiseLang ещё девять лет назад, когда мучился с ручными расчётами вероятностей. Тогда проект застрял — но теперь, с помощью современных AI-инструментов, он ожил и стал гораздо серьёзнее.
Главная идея: каждое значение в NoiseLang — это распределение вероятностей. Даже обычное число A = 5 — это дельта Дирака, у которой все «выбросы» равны пятёрке. Оператор ~ превращает константу в случайную величину: D1 ~ unif_int(1, 6) — это честный игральный кубик. При этом X + X — это строго 2X, без случайности: имена, как в математике, всегда ссылаются на один и тот же узел. Чтобы получить независимые броски, нужно писать ~ несколько раз. Ничего не вычисляется, пока ты явно не запросишь результат — например, P(X + Y < 10). В этот момент движок запускает миллионы симуляций на всех ядрах и выдаёт оценку со стандартной ошибкой.
Тяжелее всего оказалась не грамматика (парсер пишется за выходные), а рантайм. Текущая версия — это полноценный компилятор с JIT-компиляцией на базе Cranelift, бэкендом под WASM и кучей численного кода. Внутри операторы ~ и конструкторы распределений строят направленный ациклический граф (RvGraph). Из него потом генерируются три пути: столбцовый интерпретатор (эталон корректности), Cranelift JIT (всё выражение в один нативный кернел) и WASM-эмиттер для браузера. Если бэкенд не справляется — падает обратно на интерпретатор, и результаты идентичны.
Оптимизация Monte Carlo завязана на один цикл. Трюки: слияние кернела (все промежуточные значения в регистрах), встраивание PRNG xoshiro256++ и аппроксимации ln, sin, cos полиномами — это даёт ускорение в 2 раза. Но любимая фишка автора — распараллеливание RNG: вместо одной цепочки запускаются четыре независимых потока, которые out-of-order ядро перекрывает. Это оказалось быстрее ручного SIMD. На M4 Pro (14 ядер) строка P(...) выдаёт около 5,8 млрд семплов в секунду, масштабируясь в 9,6 раза с одного ядра на все. Сгенерированный кернел всего в 1,15 раза медленнее хэнд-райтенного Rust под LLVM.
Чем NoiseLang отличается от NumPy или Stan? NumPy заставляет писать симуляцию руками. Stan — объявлять модель и ждать сэмплер. NoiseLang даёт записать вероятность прямо как математику, а Monte Carlo бежит под капотом. Он проигрывает Stan и PyMC в подгонке апостериорных распределений по тысячам непрерывных наблюдений (там conditioning основан на реджекшн-семплинге) и уступает NumPy в сырой работе с массивами. Но для быстрого ответа на вероятностный вопрос, прямо с доски, он быстрее всех.
В качестве бонуса автор прикрутил демку, моделирующую, почему FM-радио устойчивее к шуму, чем AM. В NoiseLang сигнал — это тоже значение. Всё собирается в один экран: модуляция, добавление шума, демодуляция и подсчёт ошибки через mse. На выходе FM оказывается примерно в 5 раз чище при той же энергии шума.
Попробовать можно прямо в браузере на noiselang.com. Установка через npm: @noiselang/core. Функция run возвращает значение последнего выражения, а ошибки приходят с указанием места в исходнике, а не исключениями.