Примеры программ
15 программ на Глаголице с эквивалентами на F# — параллельный взгляд на то, как ключевые конструкции функциональной парадигмы выражаются в обоих языках.
О разделе
Параллельное представление позволяет увидеть, как ключевые конструкции функциональной парадигмы выражаются в Глаголице и как они соотносятся с базовым языком, на котором реализован интерпретатор.
Все примеры расположены в директории examples/:
examples/Glagol_examples/— программы на Глаголице (.gl)examples/fsharp_examples/— те же программы на F# (.fsx)examples/glagol_all_progs.glиexamples/fsharp_all_progs.fsx— все примеры в одном файлеexamples/hello.gl— простейшая программа «Привет, мир!»
Содержание
- Привет, Мир!
- Факториал
- Числа Фибоначчи
- Алгоритм Евклида (НОД)
- Поиск элемента в списке
- Цикл и генератор последовательности
- Асинхронные вычисления
- Монада успеха/ошибки
- Пользовательские типы данных
- Логические операции
- Пайплайн-оператор
- Недетерминированные вычисления (List-монада)
- Каррирование и частичное применение
- Сопоставление с образцом
- Импорт модулей
1. Привет, Мир!
Простейшая программа выводит строку в консоль с помощью встроенной функции вывод.
Глаголица
вывод("Привет Мир!")
F#
printfn "%s" "Привет Мир!"
Функция вывод — это встроенный аналог printfn из F#,
она автоматически добавляет перевод строки и умеет печатать значения любого типа.
2. Факториал
Классический пример рекурсии. На Глаголице используется ключевое слово
ПУСТЬ для объявления функции, а условные выражения записываются
через ЕСЛИ ... ТО ... ИНАЧЕ.
Глаголица
ПУСТЬ факториал(х){
ЕСЛИ х == 0 ТО { 1 }
ИНАЧЕ { х * факториал(х - 1) }
}
вывод(факториал(5))
F#
let rec factorial x =
if x = 0 then 1
else x * factorial (x - 1)
printfn "%A" (factorial 5)
В Глаголице рекурсивные функции не требуют отдельного модификатора
(как rec в F#) — функция автоматически видит саму себя.
3. Числа Фибоначчи
Ещё один пример рекурсии, демонстрирующий вложенные условия.
Глаголица
ПУСТЬ фиб(х){
ЕСЛИ х == 0 ТО { 0 }
ИНАЧЕ {
ЕСЛИ х == 1 ТО { 1 }
ИНАЧЕ { фиб(х - 1) + фиб(х - 2) }
}
}
вывод(фиб(10))
F#
let rec fib x =
if x <= 1 then x
else fib (x - 1) + fib (x - 2)
printfn "%A" (fib 10)
4. Алгоритм Евклида (НОД)
Рекурсивный алгоритм нахождения наибольшего общего делителя через вычитание.
Глаголица
ПУСТЬ нод(а, б){
ЕСЛИ а == б ТО { а }
ИНАЧЕ {
ЕСЛИ а > б ТО { нод(а - б, б) }
ИНАЧЕ { нод(а, б - а) }
}
}
вывод(нод(14, 21))
F#
let rec gcd a b =
if a = b then a
elif a > b then gcd (a - b) b
else gcd a (b - a)
printfn "%A" (gcd 14 21)
5. Поиск элемента в списке
Демонстрирует сопоставление с образцом
(СОПОСТАВИТЬ ... С) и работу со списками.
Список разбирается на голову и хвост через шаблон [голова - хвост].
Глаголица
ПУСТЬ содержит(список, элемент){
СОПОСТАВИТЬ список С {
КОГДА ПУСТО -> { ЛОЖЬ }
КОГДА [голова - хвост] -> {
ЕСЛИ голова == элемент ТО { ИСТИНА }
ИНАЧЕ { содержит(хвост, элемент) }
}
}
}
ПУСТЬ мой_список = [10, 20, 30]
вывод(содержит(мой_список, 20))
F#
let rec contains lst element =
match lst with
| [] -> false
| head :: tail ->
if head = element then true
else contains tail element
let myList = [10; 20; 30]
printfn "%A" (contains myList 20)
Соответствия:
| Глаголица | F# |
|---|---|
СОПОСТАВИТЬ x С { ... } | match x with |
КОГДА ПУСТО -> { ... } | | [] -> ... |
КОГДА [голова - хвост] | | head :: tail -> |
ИСТИНА / ЛОЖЬ | true / false |
6. Цикл и генератор последовательности
Цикл ДЛЯ пробегает по диапазону, сгенерированному функцией ОТ_ДО.
Это аналог for ... in 1..10 do в F#.
Глаголица
ПУСТЬ таблица = ДЛЯ (ч В ОТ_ДО(1, 10)) {
вывод(ч * ч)
}
F#
for i in 1..10 do
printfn "%d" (i * i)
7. Асинхронные вычисления
Глаголица поддерживает асинхронные блоки через ФОНОМ({ ... })
и ожидание результата через ДОЖДАТЬСЯ(...). Это прямой аналог
async { ... } и Async.RunSynchronously в F#.
Глаголица
ПУСТЬ долгая_задача = ФОНОМ({
ЕСЛИ ИСТИНА ТО { 42 } ИНАЧЕ { 0 }
})
ПУСТЬ результат = ДОЖДАТЬСЯ(долгая_задача)
вывод(результат)
F#
let task = async {
return if true then 42 else 0
}
let asyncResult = Async.RunSynchronously task
printfn "%A" asyncResult
8. Монада успеха/ошибки
Для безопасной обработки результатов вычислений Глаголица предоставляет монадические
конструкторы УСПЕХ(...) и оператор связывания ДАЛЕЕ_УСПЕШНО.
Это аналог Result<_,_> и Result.bind в F#.
Глаголица
ПУСТЬ старт = УСПЕХ(10)
ПУСТЬ результат = старт ДАЛЕЕ_УСПЕШНО (х) -> {
УСПЕХ(х * 2)
}
вывод(результат)
F#
let start : Result = Ok 10
let res = start |> Result.bind (fun x -> Ok(x * 2))
printfn "%A" res
Оператор ДАЛЕЕ_УСПЕШНО пропускает вычисление дальше только в случае успеха;
при ошибке цепочка прерывается.
9. Пользовательские типы данных
Глаголица позволяет определять структурные типы (записи) через ключевое слово
ТИП. Поля доступны через точечную нотацию.
Глаголица
ТИП Игрок = { здоровье Int, уровень Int }
ПУСТЬ герой = Игрок { здоровье = 100, уровень = 5 }
ПУСТЬ жив_ли(персонаж){
ЕСЛИ персонаж.здоровье > 0 ТО { ИСТИНА } ИНАЧЕ { ЛОЖЬ }
}
вывод(жив_ли(герой))
F#
type Player = { Health: int; Level: int }
let hero = { Health = 100; Level = 5 }
let isAlive p =
if p.Health > 0 then true else false
printfn "%A" (isAlive hero)
10. Логические операции
Логические И, ИЛИ, НЕ — это аналоги &&, ||, not в F#.
Глаголица
ПУСТЬ проверка(а, б){
ЕСЛИ а И б ТО { ИСТИНА }
ИНАЧЕ { ЛОЖЬ }
}
вывод(проверка(ИСТИНА, ЛОЖЬ))
F#
let check a b =
if a && b then true
else false
printfn "%A" (check true false)
11. Пайплайн-оператор
Оператор ДАЛЕЕ передаёт значение слева в анонимную функцию справа —
как |> в F#. Это упрощает чтение цепочек преобразований.
Глаголица
ПУСТЬ модификатор(х){ х * 5 }
ПУСТЬ результат = 10 ДАЛЕЕ (значение) -> {
модификатор(значение)
}
вывод(результат)
F#
let modifier x = x * 5
let pipeResult = 10 |> (fun v -> modifier v)
printfn "%A" pipeResult
12. Недетерминированные вычисления (List-монада)
Конструкция ВАРИАНТЫ(...) создаёт недетерминированное значение —
программа исполняется для каждой комбинации возможных значений. Условие
ТРЕБОВАТЬ(...) отсеивает неподходящие варианты. Это удобный способ
выразить декартово произведение и фильтрацию.
Глаголица
ПУСТЬ х = ВАРИАНТЫ(1, 2, 3)
ПУСТЬ у = ВАРИАНТЫ(1, 2, 3)
ТРЕБОВАТЬ(х + у == 4)
вывод(х)
F#
let combinations =
[ for x in 1..3 do
for y in 1..3 do
if x + y = 4 then yield x ]
printfn "%A" combinations
В F# подобный эффект достигается через list comprehension с вложенными циклами и условием.
13. Каррирование и частичное применение
В Глаголице можно применить функцию частично, подставив _ вместо ещё
не известного аргумента — получится новая функция от оставшихся аргументов.
Глаголица
ПУСТЬ вычесть(п, р){ п - р }
ПУСТЬ отнятьОтДесяти = вычесть(10, _)
вывод(отнятьОтДесяти(3))
F#
let subtract a b = a - b
let subtractFromTen = subtract 10
printfn "%d" (subtractFromTen 3)
В F# каррирование автоматическое (все функции каррированы по умолчанию),
а в Глаголице оно явное — через placeholder _.
14. Сопоставление с образцом
Сопоставление с образцом — один из самых выразительных приёмов функционального программирования.
Глаголица поддерживает шаблоны для литералов, списков и подстановочного знака _.
Глаголица
ПУСТЬ описатьЧисло(х){
СОПОСТАВИТЬ х С {
КОГДА 0 -> { "Это ноль" }
КОГДА 1 -> { "Это один" }
КОГДА _ -> { "Это другое число" }
}
}
вывод(описатьЧисло(1))
ПУСТЬ проверитьСписок(сп){
СОПОСТАВИТЬ сп С {
КОГДА ПУСТО -> { "Список пустой" }
КОГДА [голова - хвост] -> { "В списке есть элементы" }
}
}
вывод(проверитьСписок([1, 2, 3]))
F#
let describeNumber x =
match x with
| 0 -> "Это ноль"
| 1 -> "Это один"
| _ -> "Это другое число"
printfn "%s" (describeNumber 1)
let checkList lst =
match lst with
| [] -> "Список пустой"
| head :: tail -> "В списке есть элементы"
printfn "%s" (checkList [1; 2; 3])
15. Импорт модулей
Глаголица поддерживает разделение программ на модули с помощью директивы
ИМПОРТ. После импорта все функции и значения из подключённого
файла становятся доступны в текущем.
Файл с функцией:
ПУСТЬ факториал(х){
ЕСЛИ х == 0 ТО { 1 }
ИНАЧЕ { х * факториал(х - 1) }
}
Файл, который импортирует:
Глаголица
ИМПОРТ ".\examples\Glagol_examples\factorial_for_import.gl"
ПУСТЬ результат = { факториал(5) }
вывод(результат)
F#
#load "factorial_for_import.fsx"
open Factorial_for_import
let result = factorial 5
printfn "%d" result
В Глаголице используется ИМПОРТ "путь/к/файлу.gl", в F# — директива
#load вместе с open.
Сводная таблица соответствий
| Конструкция | Глаголица | F# |
|---|---|---|
| Объявление значения | ПУСТЬ имя = ... | let имя = ... |
| Объявление функции | ПУСТЬ ф(х){ ... } | let ф x = ... |
| Условие | ЕСЛИ ... ТО ... ИНАЧЕ | if ... then ... else |
| Логические операторы | И, ИЛИ, НЕ | &&, ||, not |
| Литералы | ИСТИНА, ЛОЖЬ, ПУСТО | true, false, [] |
| Сопоставление | СОПОСТАВИТЬ ... С | match ... with |
| Шаблон списка | [голова - хвост] | head :: tail |
| Цикл | ДЛЯ (х В ОТ_ДО(а,б)) | for x in a..b do |
| Пайплайн | значение ДАЛЕЕ ф | значение |> ф |
| Асинхронность | ФОНОМ({...}), ДОЖДАТЬСЯ | async { ... }, RunSynchronously |
| Монада успеха | УСПЕХ, ДАЛЕЕ_УСПЕШНО | Ok, Result.bind |
| Недетерминизм | ВАРИАНТЫ, ТРЕБОВАТЬ | list comprehension с условиями |
| Структурный тип | ТИП И = { поле Тип } | type T = { Field: Type } |
| Импорт | ИМПОРТ "путь" | #load "путь" + open |
| Вывод в консоль | вывод(...) | printfn "..." ... |
| Комментарий | комментарий: ... | // ... |
Как запускать примеры
-
Глаголица: запустите интерпретатор языка, передав путь к файлу
.gl. Подробности — в разделе Запуск программ. -
F#: достаточно
dotnet fsi путь/к/файлу.fsx(требуется установленный .NET SDK).
Все примеры в обеих директориях именованы одинаково, поэтому их легко сопоставлять попарно.