Документация языка
Полное описание синтаксиса и возможностей Глаголицы — от литералов до монад и асинхронности.
Введение
Глаголица — функциональный язык программирования с синтаксисом на кириллице. Он поддерживает рекурсию, замыкания, сопоставление с образцом, монадическую обработку ошибок, асинхронные вычисления, недетерминированные вычисления (List-монада), каррирование и пайплайн-операторы.
Все ключевые слова записываются заглавными буквами на русском языке
(например, ПУСТЬ, ЕСЛИ, ИНАЧЕ, СОПОСТАВИТЬ).
Имена переменных и функций можно писать как кириллицей, так и латиницей.
Содержание
- Структура программы
- Комментарии
- Базовые типы и литералы
- Идентификаторы
- Объявление переменных и функций
- Условные выражения
- Арифметические и логические операторы
- Списки
- Сопоставление с образцом
- Лямбда-функции
- Каррирование и частичное применение
- Пайплайн-операторы
- Цикл и диапазоны
- Монада успеха/ошибки
- Асинхронность
- Недетерминированные вычисления
- Структурные типы
- Импорт модулей
- Встроенные функции
- Запуск программ
1. Структура программы
Программа на Глаголице — это последовательность выражений. Каждое выражение возвращает
значение (либо VUnit, если значение бессмысленно — например, после вывод).
ПУСТЬ х = 10
ПУСТЬ у = 20
вывод(х + у)
Программа исполняется сверху вниз. Все объявления (ПУСТЬ, ТИП)
видны в последующем коде в том же блоке.
2. Комментарии
Глаголица поддерживает два вида комментариев.
Однострочный
Начинается с комментарий: и идёт до конца строки:
комментарий: это однострочный комментарий
ПУСТЬ х = 5
Многострочный
Начинается с комментарий { ... }:
комментарий {
Здесь несколько строк
с пояснениями.
}
3. Базовые типы и литералы
| Тип | Литералы | Пример |
|---|---|---|
| Целое | целые числа | 0, 42, -7 |
| Логическое | ИСТИНА, ЛОЖЬ | ИСТИНА |
| Строка | в двойных кавычках | "Привет Мир!" |
| Пустой список | ПУСТО или [] | ПУСТО |
| Список | [элем1, элем2, ...] | [1, 2, 3] |
4. Идентификаторы
Идентификатор может содержать:
- латинские буквы (
a-z,A-Z), - кириллические буквы (
а-я,А-Я), - цифры (но не в первой позиции),
- подчёркивание
_.
Примеры допустимых имён: х, мой_список, factorial, результат_2.
Зарезервированные ключевые слова нельзя использовать в качестве идентификаторов:
ПУСТЬ, В, ЕСЛИ, ТО, ИНАЧЕ,
СОПОСТАВИТЬ, С, КОГДА, УСПЕХ, ПРОВАЛ,
ФОНОМ, ДОЖДАТЬСЯ, ТРЕБОВАТЬ, ВАРИАНТЫ,
ОТ_ДО, ИСТИНА, ЛОЖЬ, И, ИЛИ,
ПУСТО, ДАЛЕЕ, ДАЛЕЕ_УСПЕШНО.
5. Объявление переменных и функций (ПУСТЬ)
Ключевое слово ПУСТЬ объявляет имя для значения или функции.
Переменная
ПУСТЬ имя = выражение
Пример:
ПУСТЬ х = 10
ПУСТЬ сообщение = "Привет"
Функция
ПУСТЬ имя(аргумент1, аргумент2, ...){
тело
}
Пример:
ПУСТЬ сложить(а, б){
а + б
}
вывод(сложить(2, 3))
Все функции в Глаголице рекурсивны по умолчанию — функция видит саму себя в своём теле, никаких отдельных модификаторов не нужно.
ПУСТЬ факториал(х){
ЕСЛИ х == 0 ТО { 1 }
ИНАЧЕ { х * факториал(х - 1) }
}
6. Условные выражения (ЕСЛИ ... ТО ... ИНАЧЕ)
Условие — это выражение, возвращающее значение одной из двух ветвей.
ЕСЛИ условие ТО { ветвь_1 } ИНАЧЕ { ветвь_2 }
Обе ветви обязательны и заключены в фигурные скобки. Условие должно вычисляться в логическое значение.
ПУСТЬ макс(а, б){
ЕСЛИ а > б ТО { а } ИНАЧЕ { б }
}
вывод(макс(7, 12))
Условия можно вкладывать друг в друга:
ЕСЛИ х == 0 ТО { 0 }
ИНАЧЕ {
ЕСЛИ х == 1 ТО { 1 }
ИНАЧЕ { фиб(х - 1) + фиб(х - 2) }
}
7. Арифметические и логические операторы
| Оператор | Назначение | Пример |
|---|---|---|
+ | сложение | 2 + 3 |
- | вычитание | 5 - 1 |
* | умножение | 4 * 6 |
/ | целочисленное деление | 10 / 3 |
== | равенство | х == 0 |
> | больше | а > б |
И | логическое И | а И б |
ИЛИ | логическое ИЛИ | а ИЛИ б |
Приоритет от высшего к низшему: *, / →
+, - → ==, > →
И → ИЛИ → ДАЛЕЕ, ДАЛЕЕ_УСПЕШНО.
8. Списки
Список создаётся через квадратные скобки с разделителем-запятой:
ПУСТЬ числа = [1, 2, 3, 4, 5]
ПУСТЬ строки = ["раз", "два", "три"]
ПУСТЬ пусто = ПУСТО
Пустой список можно записать как ПУСТО или [].
Внутри Глаголица представляет списки как пары «голова — хвост», поэтому для разбора удобно использовать сопоставление с образцом.
9. Сопоставление с образцом (СОПОСТАВИТЬ ... С)
Сопоставление с образцом проверяет значение по нескольким шаблонам сверху вниз и выполняет ветвь первого подходящего.
СОПОСТАВИТЬ значение С {
КОГДА шаблон1 -> { выражение1 }
КОГДА шаблон2 -> { выражение2 }
...
}
Поддерживаемые шаблоны
| Шаблон | Что матчит |
|---|---|
0, 42 | конкретное целое число |
ИСТИНА, ЛОЖЬ | логические литералы |
"строка" | конкретную строку |
ПУСТО | пустой список |
[голова - хвост] | непустой список (привязывает имена) |
имя | любое значение, привязывая его к имени |
_ | любое значение без привязки |
Пример:
ПУСТЬ описать(х){
СОПОСТАВИТЬ х С {
КОГДА 0 -> { "ноль" }
КОГДА 1 -> { "один" }
КОГДА _ -> { "другое" }
}
}
Разбор списка:
ПУСТЬ длина(сп){
СОПОСТАВИТЬ сп С {
КОГДА ПУСТО -> { 0 }
КОГДА [_ - хвост] -> { 1 + длина(хвост) }
}
}
10. Лямбда-функции
Анонимная функция записывается как:
(аргумент1, аргумент2, ...) -> выражение
Пример:
ПУСТЬ удвоить = (х) -> { х * 2 }
вывод(удвоить(7))
Лямбды чаще всего используются вместе с пайплайн-операторами и встроенными функциями
высшего порядка (отобразить, отфильтровать, свернуть).
11. Каррирование и частичное применение
Чтобы получить частично применённую функцию, подставьте _
вместо ещё не известного аргумента:
ПУСТЬ вычесть(п, р){ п - р }
ПУСТЬ отнятьОтДесяти = вычесть(10, _)
вывод(отнятьОтДесяти(3)) комментарий: 7
_ — плейсхолдер: на этом месте функция «запоминает» недостающий аргумент
и возвращает новую функцию, которая ждёт его.
12. Пайплайн-операторы (ДАЛЕЕ, ДАЛЕЕ_УСПЕШНО)
ДАЛЕЕ передаёт значение слева в функцию справа:
значение ДАЛЕЕ функция
Пример:
ПУСТЬ удвоить(х){ х * 2 }
ПУСТЬ результат = 5 ДАЛЕЕ (значение) -> { удвоить(значение) }
вывод(результат) комментарий: 10
ДАЛЕЕ_УСПЕШНО — «безопасный» пайплайн для значений типа
УСПЕХ / ПРОВАЛ. Если слева УСПЕХ(v),
выполняется правая часть с распакованным v.
Если слева ПРОВАЛ, цепочка прерывается и ошибка прокидывается дальше.
ПУСТЬ результат = УСПЕХ(10) ДАЛЕЕ_УСПЕШНО (х) -> { УСПЕХ(х * 2) }
У ДАЛЕЕ_УСПЕШНО есть синонимичный знаковый оператор >>?.
13. Цикл ДЛЯ и диапазоны (ОТ_ДО)
Цикл пробегает по элементам списка и исполняет тело для каждого:
ДЛЯ (имя В коллекция) {
тело
}
Чаще всего коллекция — диапазон, построенный через ОТ_ДО(а, б):
ДЛЯ (ч В ОТ_ДО(1, 10)) {
вывод(ч * ч)
}
ОТ_ДО(1, 10) — это список [1, 2, ..., 10].
14. Монада успеха/ошибки (УСПЕХ, ПРОВАЛ)
Глаголица предоставляет встроенный тип результата:
УСПЕХ(значение)— успешное вычисление,ПРОВАЛ(ошибка)— ошибочное.
ПУСТЬ безопасное_деление(а, б){
ЕСЛИ б == 0 ТО { ПРОВАЛ("Деление на ноль") }
ИНАЧЕ { УСПЕХ(а / б) }
}
Цепочки обработки строятся через ДАЛЕЕ_УСПЕШНО:
ПУСТЬ итог = безопасное_деление(10, 2)
ДАЛЕЕ_УСПЕШНО (х) -> { УСПЕХ(х + 1) }
вывод(итог)
При появлении ПРОВАЛ все последующие шаги пропускаются.
15. Асинхронность (ФОНОМ, ДОЖДАТЬСЯ)
ФОНОМ({ ... }) запускает блок кода в фоновой задаче и возвращает «фьючер»:
ПУСТЬ задача = ФОНОМ({
комментарий: тут может быть долгое вычисление
42
})
ДОЖДАТЬСЯ(...) блокирует выполнение, пока задача не завершится,
и возвращает её результат:
ПУСТЬ результат = ДОЖДАТЬСЯ(задача)
вывод(результат) комментарий: 42
16. Недетерминированные вычисления (ВАРИАНТЫ, ТРЕБОВАТЬ)
Глаголица использует List-монаду: программа может «расщепляться» на несколько вселенных, по одной для каждого возможного значения.
ВАРИАНТЫ(а, б, в, ...) — это значение, которое одновременно равно
каждому из перечисленных:
ПУСТЬ х = ВАРИАНТЫ(1, 2, 3)
ПУСТЬ у = ВАРИАНТЫ(1, 2, 3)
ТРЕБОВАТЬ(х + у == 4)
вывод([х, у])
ТРЕБОВАТЬ(условие) отсекает все вселенные, в которых условие ложно.
В примере выше будут выведены все пары (х, у) такие, что х + у == 4.
Это удобный способ записывать переборные и комбинаторные задачи: декартовы произведения, поиск решений, задачи логики.
17. Структурные типы (ТИП)
Объявление структурного типа (записи):
ТИП ИмяТипа = { поле1 Тип1, поле2 Тип2, ... }
Пример:
ТИП Игрок = { здоровье Int, уровень Int }
Создание экземпляра:
ПУСТЬ герой = Игрок { здоровье = 100, уровень = 5 }
Доступ к полю — через точку:
вывод(герой.здоровье)
Имя типа в аннотациях полей — пометка для читателя; во время выполнения значения хранятся как именованные пары без жёсткой проверки типов.
18. Импорт модулей (ИМПОРТ)
Подключение содержимого другого файла:
ИМПОРТ "путь/к/файлу.gl"
Все объявления из импортированного файла становятся доступны после директивы:
ИМПОРТ ".\examples\Glagol_examples\factorial_for_import.gl"
ПУСТЬ результат = факториал(5)
вывод(результат)
Путь — относительный (от текущей директории запуска) или абсолютный.
19. Встроенные функции
| Функция | Назначение |
|---|---|
вывод(значение) | печатает значение в консоль |
чтение() | читает строку из стандартного ввода |
читать_файл(путь) | читает файл, возвращает УСПЕХ(содержимое) или ПРОВАЛ |
Число(строка) | парсит строку в целое |
Дробное(строка) | парсит строку в дробное число |
Строка(значение) | приводит значение к строке |
отобразить(ф)(список) | применяет функцию к каждому элементу списка |
отфильтровать(ф)(список) | оставляет элементы, для которых функция вернула ИСТИНА |
свернуть(ф)(список) | сворачивает список слева, начиная с первого элемента |
взять_пока(ф)(список) | берёт элементы с начала, пока предикат истинен |
Все функции высшего порядка (отобразить, отфильтровать и т.д.)
каррированы — сначала передаётся функция, затем список.
ПУСТЬ удвоить(х){ х * 2 }
ПУСТЬ удвоенные = отобразить(удвоить)([1, 2, 3])
вывод(удвоенные)
20. Запуск программ
Запуск файла
dotnet run --project src -- путь/к/файлу.gl
Файл должен иметь расширение .gl.
REPL-режим
dotnet run --project src -- --repl
В REPL пустая строка завершает сессию. Многострочный ввод можно завершить строкой ;;.
Для удобной разработки доступно расширение для VS Code, а готовые примеры — в разделе Примеры программ.