Полярные типы данных в Edva

Полярные типы данных (Ramifications) в языке Эдва (Edva): единая замена для bool, Option и Result
В большинстве языков программирования понятия «истина/ложь», «значение есть/значения нет» и «успех/ошибка» живут в разных мирах. Для первого существует примитив bool и конструкции if/else, для второго — Option<T> (Maybe a), для третьего — Result<T, E> (Either a b). У каждого из них свои конструкторы (true/false, Some/None, Ok/Err) и свой набор комбинаторов.
Системный язык программирования Edva, спроектированный без единого ключевого слова, сводит все бинарные исходы к единому примитиву на уровне системы типов — алгебраическим разветвлениям (Algebraic Ramifications, или коротко — Rams).
Четыре формы полярного типа и представление в памяти
В Эдве любой бинарный исход описывается типом с двумя полюсами: положительным (левым) и отрицательным (правым). В зависимсти от того, несут ли полюса полезную нагрузку, существует ровно четыре формы:
Форма типа | Положительный полюс | Отрицательный полюс | Что заменяет в классических языках |
|
|
|
|
|
|
|
|
|
|
| Статус выполнения ( |
| <+ value -> | <- error +> |
|
На уровне LLVM IR значения полярных типов не требуют аллокаций в куче или сложных вложенных тегов — они укладываются в компактное необёрнутое (unboxed) представление { i1, i64 } (бит полярности плюс полезная нагрузка), а в случаях, когда тип уже представляет собой указатель, не нужен даже бит полярности, поскольку второй полюс можно выразить нулевым адресом, и представление сокращается до { i64 }.
Конструкторы полюсов
Для явного создания значений полярного типа используются симметричные символьные конструкторы:
Положительный полюс:
<+>,<+ val +>,<++>,<+ val ->(пустой успех или успех со значениемval).Отрицательный полюс:
<->,<-->,<- err ->,<- err +>(пустая неудача или неудача со значениемerr).
Взаимодействие с оператором выбора и стражами | и [...]
Поскольку в Edva нет ключевых слов if, else, match или switch, управление потоком строится на операторе выбора, который выглядит так:
значение [страж ветвь]+
Для обычных значений стражи в квадратных скобках проверяют равенство или предикат, а | выступает веткой по умолчанию:
classify = score =>
score [100] "perfect"
[99, 98] "almost perfect"
[> 90] "distinction"
[> 50] "pass"
| "fail"
Когда же слева от оператора выбора | оказывается полярный тип (ramification), срабатывает позиционное сопоставление:
первая ветка после
|обрабатывает положительный полюс (+),вторая ветка после
|обрабатывает отрицательный полюс (-).
Если полюс несет значение, внутри ветки к нему можно обратиться через позиционный плейсхолдер _ (или секцию оператора):
// Функция возвращает < Int | > (аналог Option<Int>)
res = find_target(10, 7)
// Первая ветка берет значение из <+ val +>, вторая срабатывает на <-->
res | print_int(_) | print $ "Not found"
Никаких if let Some(x) = res или match res { Some(x) => ..., None => ... }: полярность значения напрямую выбирает нужную ветвь выражения.
Циклы как генераторы полярных типов (>--)
В императивных языках поиск элемента в цикле обычно требует мутабельного флага found = false или досрочного return из функции. В Edva циклы (@) являются выражениями, которые с помощью оператора выхода >-- естественным образом возвращают < T | >:
// Цикл ищет цель в диапазоне 0..count и возвращает < Int | >
find_target: Int, Int => < Int | >
find_target = count, target =>
count @ i =>
i [target] --> // если i == target, прерываем цикл (break)
>--
target // значение при срабатывании -->
Механика работы >--:
Если внутри цикла сработал оператор прерывания
-->, блок после>--вычисляет результирующее значение и автоматически упаковывает его в положительный полюс<+ target +>.Если цикл прошел до конца без прерываний, выражение целиком возвращает отрицательный полюс
<-->.
Полученный результат тут же готов к передаче в оператор выбора | или дальше по конвейеру.
Композиция и обработка ошибок: $>> и --!
Когда функции возвращают < T | E > или < T | >, Edva предлагает два способа композиции без ручного разбора веток: конвейерное монадическое связывание и постфиксное пробрасывание.
1. Монадический bind ($>>)
Оператор $>> пропускает положительный полюс через цепочку функций, а при возникновении отрицательного полюса (<- err -> или <-->) коротко замыкает вычисление и пробрасывает его на выход:
find_user: String => < User | Error >
find_user = id =>
query_db(id) $>> validate $>> (<+ _ +>)
// выражение с подчёркиванием в скобках это лямбда, эквиалентно x => <+ x +>Если query_db или validate вернут отрицательный полюс с ошибкой, вся цепочка немедленно завершится с этим же отрицательным полюсом типа Error: <- error ->.
2. Постфиксная распаковка и ранний возврат (--!)
Для последовательного кода, где нужно распаковать несколько полярных значений подряд, используется постфиксный оператор --!:
load_config: String => < Config | Error >
load_config = path =>
raw = io::read_file(path)--!
cfg = json::parse(raw)--!
<+ cfg +>
Если io::read_file(path) возвращает <+ content +>, оператор --! извлекает content и связывает его с raw. Если же вернулся <- err ->, выполнение load_config прерывается (по аналогии с тем, как --> прерывает цикл), возвращая ошибку вызывающей стороне.
Итог: единая алгебра вместо зоопарка типов
За счет объединения булевой логики, опциональных типов и результатов с ошибками в четыре формы < ... | ... >, Edva избавляется от дублирования концепций:
Вместо отдельных
bool,OptionиResult— единый параметризуемый тип{ i1, i64 }.Вместо
if/else,match,.unwrap_or()иif let— единый оператор выбора|с позиционными ветками.Вместо ручных флагов выхода из циклов — оператор
>--, связывающий управление циклом напрямую с системой типов.
Ссылки
репозиторий Edva https://github.com/edva-lang/edva
документация Edva https://edva-lang.github.io
экосистема Edva (примеры файлового менеджера, библиотек и компиляции в WASM)
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.