NewLang — это язык программирования высокого уровня общего назначения c базовым синтаксисом на основе грамматических правил. С помощью макросов препроцесора, базовый синтаксис легко преобразуется в DSL на основе ключевых слов.
Тензорные вычисления и рациональные числа не ограниченной точности поддерживаются на уровне синтаксиса языка и базовых типов данных без использования дополнительных библиотек.
Модель управления памятью на основе владения не трубет использования сборщика мусора и исключет основные ошибки еще на этапе компиляции исходного текста программы.
Основные свойства и особенности языка:
- возможность работы как в режиме интерпретатора, так и компилятора*
- динамическая и статическая типизация с возможностью указания типов в явном виде
- статическая типизация является условно-строгой (автоматическое приведение типов отсутствует, но допускается преобразование между некоторыми типами данных. Например, целое число может быть автоматически преобразовано в вещественное или рациональное, но не наоборот)
- автоматическое управление памятью без сборщика мусора на основе владения*
- ООП* в виде явного наследования классов и «утиная типизация»
- на уровне синтаксиса поддерживается несколько типов функций (обычные и чистые функции без побочных эффектов)
- необязательные и именованные параметры функций
- простая интеграция с уже существующими программными библиотеками (в том числе импорт нативных переменных, функций и классов* из С/С++.)
- имеется REPL (read-eval-print loop — «цикл: чтение — вычисление — вывод»)
- символьные вычисления**
*) Данные возможности запланированы к реализации
**) Символьные вычисления поддерживаются на уровне синтаксиса, но не реализованы
Зачем нужен NewLang?
У всех современных языков программирования происходит постоянное развитие (усложнение) синтаксиса по мере выхода новых версий.
Это является своего рода платой за появление новых возможностей языка и воспринимается пользователями как естественное явление.
Но одновременно является и серьезной проблемой, так как с выходом новых версий языка в него добавляются новые ключевые слова и синтаксические конструкции, что неизбежно повышает порог входа для всех новых пользователей.
Еще одним следствием этого процесса становится постоянное увеличение сложности разработки и поддержки уже созданных программных продуктов, когда старый программный код дорабатывается с применением уже новых стандартов и постоянным увеличением старого легаси кода.
У NewLang сложность языковых конструкций ограничена естественным образом за счет разделения синтаксиса языка на несколько частей, что упрощает его изучение и использование.
Основной (базовый) синтаксис — на системе строгих грамматических правил.
Синтаксис DSL (domain-specific language) — хотя базовый синтаксис самодостаточен и полснотью покрывает все возможные сценарии использования,
но его применение разработчиками напрямую не всегда эффекстивно с точки зрения последующего чтения исходноиков.
Поэтому более правильным вариантом написания исходного кода программы будет применение предметно-ориентированного языка,
который реализуется с помощью макросов препроцессора и превращает базовый синтаксис на основе грамматических правил
в синтаксис на основе ключевых слов.
Расширенный синтаксис — программные вставки на языке реализации (С/С++), когда основного или DSL синтаксиса становится недостаточно.
Еще одно неудобство современных языков в том, что большинство из них были созданы еще до начала эпохи машинного обучения, поэтому тензорные вычисления у них выполнены в виде отдельных библиотек. Это же касается и вычислений с неограниченной точностью, которые также требуют использования дополнительных библиотечных функций.
У NewLang тензорные вычисления и рациональные числа неограниченной точности доступны «из коробки».
Они поддерживаются на уровне синтаксиса для удобной записи литералов,
а простые арифметические типы данных являются скалярами (тензорами нулевой размерности).
Реализация тензорных вычислений сделана на базе библиотеки libtorch,
а рациональные числа с использованием OpenSSL.
Пример скрипта Hello world! на NewLang
#!../output/nlc --eval
hello(str) := {
# Импорт и вызов функции printf стандартной библиотеки
printf(format:FmtChar, ...):Int32 := %printf...;
printf('call: %s', $str);
$str;
};
hello('Привет, мир!');
Вывод:
call: Привет, мир!
Привет, мир!
Пример вычисления факториала 40 на NewLang (базовый синтаксис)
#!../output/nlc --eval
fact := 1\1; # Рациональное число 1 (без ограничения точности)
mult := 40..1..-1?; # Итератор из диапазона для множителей от 40 до 2
[mult ?!] <-> { # Цикл, пока не закончатся данные итератора
fact *= mult !; # Получить текущий множитель и перейти на следующий элемент итератора
};
fact # Вывести итоговый результат
Вывод:
815915283247897734345611269596115894272000000000\1
Тот же код с использованием DSL синтаксиса
#!../output/nlc --eval
fact := 1\1;
mult := iter( 40..1..-1 );
while( curr(mult) ) {
fact *= next(mult);
};
fact;
Вывод:
815915283247897734345611269596115894272000000000\1