Micro, v2.3, описание
Posted on

Micro — интерпретируемый высокоуровневый язык программирования. Поддерживает функциональную парадигму, обладает сильной полустатической типизацией и сборкой мусора.
Общее описание
Вызовы функций
Программы на данном языке представляют собой последовательность вызовов функций. Вызов функции записывается следующим образом:
function, {parameter}
При этом и function, и parameter могут быть либо константами (числовыми или строковыми), либо точно такими же вызовами функций.
При исполнении сначала вычисляется выражение для самой функции. По результату определяется арность функции. Затем вычисляется нужное число аргументов. И наконец они передаются функции.
Например, имеем следующее выражение:
+ 2 * 5 12
Первой интерпретатор встречает функцию +. Она имеет арность 2. Интерпретатор начинает вычислять 2 аргумента для неё. Первый равен 2. При вычислении второго же обнаруживается новая функция — *, которая также имеет арность 2. Поэтому начинается расчёт 2 аргументов уже для функции *. Это 5 и 12. После этого интерпретатор может вычислить результат выражения * 5 12 (это 60), который и будет вторым аргументом для функции +. Затем интерпретатор может вычислить результат всего выражения (+ 2 60) — 62.
Разбиение на токены
Константы:
- числа —
/\d+(\.\d+)?(e-?\d+)?/или/0x[A-Fa-f0-9]+/, например:23,4.2,0x74; - символы —
/'(\\.|\\x[A-Fa-f0-9]{2}|[^'])'/, например:'t','\'','\x74'; - строки —
/"(\\.|\\x[A-Fa-f0-9]{2}|[^"])*"/, например:"","test","Say \"Hello!\".","\x74es\x74".
Идентификаторы:
- буквенные —
/[a-z_]+/i - ("fn" | "let" | "as"); - пунктуационные —
/[[:punct:]]+/ - /['"_():;]/.
Идентификаторы разных типов и любые константы можно чередовать без разделения их пробелами. Например, код ~sin2.3 будет преобразован в следующую последовательность токенов: ~, sin и 2.3.
Пользовательские функции
Пользователь может объявлять собственные функции:
"fn", [name], "(", {argument, type}, ")", type,
{entity},
";"
name и argument — любые идентификаторы. Имя функции указывать необязательно.
Если имя функции указано, то данная функция доступна для вызова посредством этого имени ниже в текущей области видимости, а также внутри себя самой. Анонимные функции доступны для вызова только после передачи их в другие функции в качестве аргументов.
Функции можно переопределять.
Результатом выполнения функции является последнее вычисленное внутри неё значение.
Замыкания
Внутри функции доступны все идентификаторы из внешних для функции областей видимости. Если параметры функции имеют имя, совпадающее с одним из этих идентификаторов, то параметр перекрывает этот идентификатор.
Переменные
"let", [name], type,
{entity},
";"
name — любой идентификатор. Имя переменной указывать необязательно.
Если имя переменной указано, то данная переменная доступна посредством этого имени ниже в текущей области видимости. При этом внутри определения самой себя она доступна не будет.
Присваивание переменным нового значения не поддерживается, но поддерживается переопределение переменных.
Результатом переменной является последнее вычисленное внутри её определения значение.
Форсирование вычислений
Основное отличие переменных от замыканий в том, что замыкания вычисляются только в месте своего вызова, в то время как переменные — непосредственно в месте определения. Таким образом значение переменной вычисляется ровно один раз, а результат замыкания столько раз, сколько раз замыкание было вызвано.
Предположим, мы хотим напечатать одно целое случайное число от 10 до 20 дважды. При помощи замыканий это можно было бы попытаться сделать следующим образом:
fn random_number()
trunc + 10 * 10 random
;
out str random_number
out str random_number
Однако при запуске скорее всего получится что-то подобное: 1710. Так происходит потому, что замыкание random_number вызывается дважды, соответственно, результат её вызова так же разный.
Если же переписать данный пример при помощи переменных:
let random_number trunc + 10 * 10 random;
out str random_number
out str random_number
То результат будет всегда ожидаемым, например: 1212.
Переопределение переменных
Второе важное отличие переменных от замыканий в том, что именованные замыкания доступны внутри определения самих себя, а именованные переменные нет.
Поэтому при попытке обращения к замыканию внутри него самого произойдёт рекурсивный вызов (подробнее о рекурсии см. ниже). А при попытке обращения к переменной внутри её определения произойдёт обращение к одноимённой переменной, определённой во внешней по отношению к этому определению области видимости.
Допустим, мы хотим прибавить число к некоторой переменной. Используем в качестве переменных замыкания:
fn number() 2; nb (1)
fn number() + number 3; nb (2)
В строке (2) внутри определения замыкания есть обращение к замыканию number. Можно подумать, что произойдёт обращение к замыканию, определённому в строке (1), однако это не так. Обращение будет к замыканию, определённому в строке (2), и мы получим рекурсивный вызов (и не дождёмся результата).
При использовании же переменных получим иную картину:
let number 2; nb (1)
let number + number 3; nb (2)
Здесь обращение к переменной number в строке (2), как и ожидается, будет к переменной, определённой в строке (1). Таким образом после выполнения строки (2) значение переменной number станет равным 5.
Полустатическая типизация
Все значения в языке разделяются на простые и вызываемые. К вызываемым относятся функции арности больше 0, к простым — все остальные типы и функции арности 0.
Типы для простых значений не указываются. Для вызываемых значений требуется указание типа для аргументов и результата функций. Тип представляет собой список из арности функции и аналогичного типа для результата функции, начинающийся и разделяемый символом :.
Например, тип :5:12:23 обозначает функцию арности 5, которая возвращает функцию арности 12, которая возвращает функцию арности 23.
Преобразование типа
"as", "(", {entity}, ")", type
Преобразование типа позволяет изменить тип выражения. При этом тип меняется только у последнего вычисленного внутри скобок значения. Также вычисление значения производится в месте преобразования (см. форсирование вычислений выше).
При помощи преобразования можно в том числе сделать простое значение вызываемым. Например, имеем следующее определение функции:
fn add()
fn(x y)
+ x y
;
;
Обратите внимание, что тип результата функции add не указан, таким образом данная функция возвращает простое значение. Вызвать данную функцию обычным образом (add 2 3) не представляется возможным. Однако при помощи преобразования типа функция может быть вызвана следующим образом:
as(add):2 2 3
Также преобразование типа удобно использовать для вызова функции непосредственно в месте её определения. Например:
as(
fn(x y)
+ 2 3
;
):2 2 3
Стоить также заметить, что обратное преобразование, то есть вызываемого значения в простое, невозможно из-за особенностей парсера.
Циклический вызов функций
В языке функции арности 0 эквивалентны значению своего результата.
Это означает, что когда интерпретатор встречает функцию арности 0, он начинает циклически её вызывать до тех пор, пока результат вызова не перестанет быть функцией арности 0.
Допустим, имеется определение:
fn answer()
fn()
fn()
42
;
;
;
Тогда, вызов функции answer будет эквивалентен значению 42.
Циклический вызов может остановиться не только на простом значении, но и на вызываемом. Допустим, имеется определение:
fn add():0:0:2
fn():0:2
fn():2
fn(x y)
+ x y
;
;
;
;
Тогда, вызов функции add 2 3 вернёт значение 5.
Рекурсия
Простой рекурсивный вызов невозможен — интерпретатор имеет низкий предел на глубину рекурсии. Чтобы обойти его, используется упаковка вызовов.
В рантайме имеется функция >@, которая упаковывает свой аргумент, не вызывая его. Так как упаковываемый вызов не вычисляется, а результат функции не является функцией, циклического вызова не происходит.
Так же в рантайме имеется функция <<@, которая производит циклическую распаковку своего аргумента — она циклически распаковывает свой аргумент до тех пор, пока результат вызова не перестанет быть упакованным.
Это позволяет заменить рекурсию на циклический вызов. Допустим, нам надо узнать длину списка. Рекурсивный вариант функции:
fn size(list)
fn _size(list result)
if != [] list
fn() _size tail list + result 1;
fn() result;
;
_size list 0
;
Данный вариант не сможет обрабатывать слишком длинные списки (упрётся в максимальную глубину рекурсии). А вариант функции с упаковкой сможет:
fn size(list)
fn _size(list result)
if != [] list
nb рекурсия здесь остановится...
>@fn() _size tail list + result 1;
fn() result;
;
nb ...а здесь она будет заменена на циклический вызов
<<@_size list 0
;
Исходники
Файлы исходного кода должны быть в кодировке ASCII и иметь концы строк как в UNIX (LF).
Ключевые слова
3 ключевых слова: fn, let, as.
Типы
Типизация: сильная полустатическая.
Менеджмент памяти: сборка мусора.
Копирование: по ссылке.
Хранение:
- ссылки — на стеке;
- значения — в куче.
Нулевой тип
Название: nil.
Тип: фиктивный тип; не хранит значение, а служит маркером его отсутствия; существует единственное значение данного типа.
Определение: значение данного типа доступно через вызов функции рантайма nil.
Вещественные числа
Название: num.
Тип: с плавающей запятой, 8 байт.
Определение:
/\d+(\.\d+)?(e-?\d+)?/
/0x[A-Fa-f0-9]+/
/'(\\.|\\x[A-Fa-f0-9]{2}|[^'])'/
Списки
Название: list.
Тип: LISP-подобный список — или пустой список, или пара из головы и хвоста, где голова может иметь любой тип (и является хранимым элементом), а хвост является аналогичным списком.
Определение:
- пустого списка — через вызов функции рантайма
[]; - списка из головы и хвоста — через вызов функции рантайма
,.
Доступ к элементам:
- к количеству элементов — через вызов функции рантайма
size; - к голове списка — через вызов функции рантайма
head; - к хвосту списка — через вызов функции рантайма
tail; - к элементу по индексу — через вызов функции рантайма
..
Строки
Строками являются списки, хранящие коды символов. Используется кодировка ASCII.
Определение: /"(\\.|\\x[A-Fa-f0-9]{2}|[^"])*"/.
Хеш-таблицы
Название: hash.
Тип: ассоциативный массив, реализованный через хеш-таблицу; порядок ключей не гарантируется.
Определение:
- пустой хеш-таблицы — через вызов функции рантайма
{}; - новой хеш-таблицы из старой и пары ключа и значения — через вызов функции рантайма
#; - новой хеш-таблицы из старой без определённого ключа — через вызов функции рантайма
#.
Доступ:
- к количеству пар ключей и значений — через вызов функции рантайма
size; - к списку ключей — через вызов функции рантайма
keys; - к значению по ключу — через вызов функции рантайма
..
Паки
Название: pack.
Тип: обёртка над значением; единственное предназначение — остановка автоматического вызова замыканий нулевой арности.
Определение: оборачивание значения в пак доступно через вызов функции рантайма >@.
Доступ к обёрнутому значению:
- однократный доступ (на один уровень вглубь) — через вызов функции рантайма
<@; - итеративный доступ (на максимальный уровень вглубь) — через вызов функции рантайма
<<@; функция итеративно разворачивает значение до тех пор, пока результат является обёрнутым значением.
Замыкания
Название: closure.
Объявление:
"fn", [identifier], "(", {identifier, {":", INTEGRAL NUMBER}}, ")", {":", INTEGRAL NUMBER},
{entity},
";"
Здесь первый identifier — имя замыкания, по которому оно будет доступно ниже в текущей области видимости, а также внутри самого себя, а все последующие identifier — имена аргументов замыкания.
{":", INTEGRAL NUMBER} — определение типа аргументов замыкания и результата замыкания (в последнем случае). Тип указывается только для замыканий (полустатическая типизация) и является списком арностей этих замыканий и их результатов.
Перегрузка замыканий не поддерживается, но поддерживается их переопределение.
Вызов замыкания: entity, entity, {entity}.
Здесь первая entity — идентификатор, являющийся замыканием, или аналогичный вызов замыкания (вложенный вызов), возвращающий замыкание, а все последующие entity — аргументы.
Логический тип
В качестве значений логического типа используются значения других типов:
- ложным логическим значением являются:
- значение
nil; - число 0;
- пустой список;
- пустые хеш-таблицы;
- значение
- истинным логическим значением являются:
- числа, отличные от 0;
- непустые списки;
- непустые хеш-таблицы;
- любые паки;
- любые замыкания.
Операции
Определение переменных
"let", [identifier], {":", INTEGRAL NUMBER},
{entity},
";"
Здесь identifier — имя переменной, по которому она будет доступна ниже в текущей области видимости. При этом внутри определения самой себя она доступна не будет.
{":", INTEGRAL NUMBER} — определение типа переменной. Тип указывается только для замыканий (полустатическая типизация) и является списком арностей этих замыканий и их результатов.
Присваивание переменным нового значения не поддерживается, но поддерживается переопределение переменных.
Преобразование типа
"as", "(", {entity}, ")", {":", INTEGRAL NUMBER}
Управляющие конструкции
Условие
В качестве условного оператора используется функция рантайма if:
"if", condition,
true value,
false value
Здесь:
condition— это вызов замыкания; его результат трактуется как значение логического типа;true value— это вызов замыкания; его значение возвращается, если результатconditionявляется истинным логическим значением;false value— это вызов замыкания; его значение возвращается, если результатconditionявляется ложным логическим значением.
Стоит учесть, что и true value, и false value вычисляются до выбора значения результата. Поэтому, если их вычисление производит побочные эффекты, нужно обернуть их в замыкания:
if condition
fn() true value;
fn() false value;
Цикл
Отсутствует.
Точка входа
Отсутствует. Интерпретатор исполняет весь предоставленный код в порядке его следования.
Комментарии
Шебанг: /^#!.*/.
Однострочные: /(?<![A-Za-z_])nb(?![:A-Za-z_]).*/.
Многострочные: /(?<![A-Za-z_])nb:.*?(?<![A-Za-z_])nb;/s.
Модульность
Тип: включением кода как текста и его последующим исполнением.
Для включения кода используется функция рантайма load:
load filename
Здесь filename — это вызов замыкания, результат которого должен быть строкой и содержать относительный путь к файлу с кодом.
Функция ищет указанный файл, читает его и исполняет, после чего возвращает полученный результат.
Функция кеширует свой результат по абсолютному пути к указанному файлу. Таким образом каждый конкретный файл исполняется только один раз, вне зависимости от того, сколько раз он загружался.
Поиск файла
Поиск указанного файла осуществляется в несколько этапов. Функция по очереди перебирает следующие возможные места расположения файла:
- директория того скрипта, из которого был осуществлён вызов функции
load; - директория
vendor, расположенная в директории того скрипта, который был передан интерпретатору; - директории, указанные в переменной окружения
MICRO_LIBRARY(перечисляются через символ:; перебираются в обратном порядке); - директория установки pip-пакета интерпретатора.
В каждом месте расположения функция по очереди пытается найти следующие файлы:
- файл, непосредственно указанный в функции
load; - файл, указанный в функции
load, с добавленным расширением.micro; - файл
__main__.micro, лежащий в директории, указанной в функцииload.
Шебанг
Интерпретатор поддерживает шебанг (то есть игнорирует его). Шебанг может выглядеть, например, так: #!/usr/bin/env micro.
Полная грамматика
program = entity list;
entity list = {entity};
entity = INTEGRAL NUMBER
| HEXADECIMAL NUMBER
| REAL NUMBER
| CHARACTER
| STRING
| identifier
| assignment
| cast
| function definition
| function call;
key words = "fn" | "let" | "as";
identifier = (ALPHABETIC IDENTIFIER - key words)
| (PUNCTUATION IDENTIFIER - ? /['"_():;]/ ?);
assignment = "let", [identifier], type,
entity list,
";";
cast = "as", "(", entity list, ")", type;
function definition = "fn", [identifier], "(", {identifier, type}, ")", type,
entity list,
";";
type = {":", INTEGRAL NUMBER};
function call = entity, entity, {entity};
SHEBANG COMMENT = ? /^#!.*/ ?;
SINGLE-LINE COMMENT = ? /(?<![A-Za-z_])nb(?![:A-Za-z_]).*/ ?;
MULTILINE COMMENT = ? /(?<![A-Za-z_])nb:.*?(?<![A-Za-z_])nb;/s ?;
INTEGRAL NUMBER = ? /\d+/ ?;
HEXADECIMAL NUMBER = ? /0x[A-Fa-f0-9]+/ ?;
REAL NUMBER = ? /\d+(((\.\d+)(e-?\d+))|(\.\d+)|(e-?\d+))/ ?;
CHARACTER = ? /'(\\.|\\x[A-Fa-f0-9]{2}|[^'])'/ ?;
STRING = ? /"(\\.|\\x[A-Fa-f0-9]{2}|[^"])*"/ ?;
ALPHABETIC IDENTIFIER = ? /[a-z_]+/i ?;
PUNCTUATION IDENTIFIER = ? /[[:punct:]]+/ ?;
Рантайм
- общие функции:
nil(): nil— возвращает значение нулевого типа;type(x: any): str— возвращает имя типа переданного значения;==(x: any, y: any): bool— равенство;!=(x: any, y: any): bool— неравенство;!(x: any): bool— логическое отрицание;&&(x: any, y: any): any— конъюнкция; функция является ленивой —yвычисляется только при необходимости (то есть когдаxистинен); возвращается вычисленное значение;||(x: any, y: any): any— дизъюнкция; функция является ленивой —yвычисляется только при необходимости (то есть когдаxложен); возвращается вычисленное значение;??(value: any, default: any): any— возвращаетvalue, если оно не равноnil; в противном случае возвращаетсяdefault;if(condition: bool, true_value: any, false_value: any): any— выбор: еслиconditionистинно, возвращаетtrue_value, иначе —false_value; функция является ленивой — вычисляется только возвращаемое значение;+(x: num|list<any>|hash<any, any>, y: num|list<any>|hash<any, any>): num|list<any>|hash<any, any>— возвращает результат комбинирования переданных аргументов:- если оба аргумента имеют тип
num, то функция возвращает результат их сложения; - если оба аргумента имеют тип
list<any>, то функция возвращает результат их конкатенации; - если оба аргумента имеют тип
hash<any, any>, то функция возвращает результат их слияния;
- если оба аргумента имеют тип
size(x: list<any>|hash<any, any>|pack<any>): num— возвращает размер (длину) переданного аргумента;.(index: any, container: list<any>|hash<any, any>|pack<any>): any— возвращает элементindexиз контейнераcontainer:- если
containerимеет типlist<any>, то функция возвращает элемент с индексомindex; если индекс отрицателен, он трактуется как номер элемента с конца списка; если индекс выходит за границы списка, то функция возвращаетnil; - если
containerимеет типhash<any, any>, то функция возвращает соответствующее ключуindexзначение; если указанный ключ отсутствует в хеш-таблице, функция возвращаетnil; - если
containerимеет типpack<any>, то он трактуется как список длиной 1;
- если
- функции для работы с логическими значениями:
false(): bool— возвращает ложное логическое значение (число 0);true(): bool— возвращает истинное логическое значение (число 1);bool(x: any): bool— преобразует значение в логический тип: возвращает строго 0 или 1;
- функции для работы с числами:
<(x: num, y: num): bool— меньше;<=(x: num, y: num): bool— меньше или равно;>(x: num, y: num): bool— больше;>=(x: num, y: num): bool— больше или равно;_(x: num): num— унарный минус;++(x: num): num— инкремент;--(x: num): num— декремент;-(x: num, y: num): num— вычитание;*(x: num, y: num): num— умножение;/(x: num, y: num): num— деление;%(x: num, y: num): num— остаток от деления;- битовые функции:
&(x: num, y: num): num— побитовое И;|(x: num, y: num): num— побитовое ИЛИ;^(x: num, y: num): num— побитовое исключающее ИЛИ;<<(x: num, y: num): num— сдвиг влево;>>(x: num, y: num): num— арифметический сдвиг вправо;>>>(x: num, y: num): num— логический сдвиг вправо;~(x: num): num— побитовое НЕ;
- математические функции:
- математические константы:
nan(): num;inf(): num;pi(): num;e(): num;
floor(x: num): num;ceil(x: num): num;trunc(x: num): num;round(x: num): num;sin(x: num): num;cos(x: num): num;tn(x: num): num;arcsin(x: num): num;arccos(x: num): num;arctn(x: num): num;angle(x: num, y: num): num— atan2;pow(base: num, exponent: num): num;sqrt(x: num): num;exp(x: num): num;ln(x: num): num;lg(x: num): num;abs(x: num): num;is_nan(x: num): bool;- генерация псевдослучайных чисел:
seed(x: any): nil— устанавливает начальное состояние генератора псевдослучайных чисел; еслиxравенnil, то для генерации начального состояния используется системный источник энтропии, а если тот недоступен — системное время; еслиxимеет любое другое значение, то для генерации начального состояния используется хеш отx;random(): num— возвращает псевдослучайное число в диапазоне [0; 1);
- математические константы:
- функции для работы со списками:
[](): list<any>— возвращает пустой список;,(head: any, tail: list<any>): list<any>— конструирует новый список из переданных головы и хвоста;head(list: list<any>): any— возвращает голову переданного списка, если он не пуст; в противном случае возвращаетсяnil;tail(list: list<any>): nil|list<any>— возвращает хвост переданного списка, если он не пуст; в противном случае возвращаетсяnil;
- функции для работы со строками:
num(x: str): num— парсит число из строки;str(x: any): str— преобразует переданное значение в строку;strb(x: bool): str— преобразует переданное логическое значение в строку: еслиxистинно, возвращает"true", иначе —"false";strs(x: str): str— преобразует переданную строку в другую строку, экранируя её символы и окружая всю строку кавычками;strl(x: list<str>): str— преобразует переданный список строк в строку, отображая при этом строки как строки;strh(x: hash<str, any>): str— преобразует переданную хеш-таблицу, у которой ключи имеют строковый тип, в строку, отображая при этом ключи как строки;strhh(x: hash<str, str>): str— преобразует переданную хеш-таблицу, у которой и ключи, и значения имеют строковый тип, в строку, отображая при этом и ключи, и значения как строки;
- функции для работы с хеш-таблицами:
{}(): hash<any, any>— возвращает пустую хеш-таблицу;#(key: any, value: any, hash: hash<any, any>): hash<any, any>— еслиvalueне равноnil, то возвращает новую хеш-таблицу, в которую было добавлено значениеvalueс ключомkey; еслиvalueравноnil, то возврашает новую хеш-таблицу, из которой было удалено значение с ключомkey;keys(hash: hash<any, any>): list<any>— возвращает список ключей хеш-таблицыhash;
- функции для упаковки:
>@(x: any): pack<any>— упаковывает переданное значение без его предварительного вычисления;<@(x: pack<any>): any— распаковывает переданное значение;<<@(x: pack<any>): any— распаковывает переданное значение в цикле до тех пор, пока результат является упакованным значением;
- системные функции:
load(filename: str): any— загружает файл скриптаfilename, выполняет его и возвращает полученный результат;is_main(): bool— возвращает истину, если файл, в котором она была вызвана, был передан для загрузки непосредственно интерпретатору, и ложь — если был загружен посредством функцииload;args(): list<str>— возвращает список аргументов командной строки, причём первым аргументом будет путь к файлу скрипта; если же код скрипта был прочитан с stdin, первым аргументом будет строка"__stdin__";env(name: str): nil|str— возвращает значение указанной переменной окружения, если она установлена; в противном случае возвращаетсяnil; также интерпретатором осуществляется загрузка.env-конфига из текущей рабочей директории;time(): num— возвращает текущее UNIX-время по UTC;sleep(seconds: num): nil— останавливает выполнение скрипта на указанное количество секунд;secondsможет быть вещественным числом;exit(status: nil|num|str): nil— завершает выполнение скрипта; дополнительное поведение зависит от переданного статуса:- если
statusравенnil, то код возврата будет равен 0; - если
statusимеет типnumи находится в диапазоне [0, 127], то код возврата будет равенstatus; - если
statusимеет типstr, то код возврата будет равен 1, аstatusбудет выведен в stderr (вместе с дополнительным символом'\n'в конце);
- если
- функции для ввода/вывода:
in(number: nil|num): str— считывает указанное количество символов из stdin и возвращает их в виде строки; если количество будет отрицательным или вместо него будет переданnil, то будут считаны все доступные символы;inln(number: nil|num): str— считывает указанное количество символов из stdin и возвращает их в виде строки; если количество будет отрицательным или вместо него будет переданnil, то будут считаны все символы до символа'\n'или, если он отсутствует, все доступные символы;out(string: str): nil— выводит переданную строку в stdout;outln(string: str): nil— выводит переданную строку в stdout и переводит строку (добавляет символ'\n');err(string: str): nil— выводит переданную строку в stderr;errln(string: str): nil— выводит переданную строку в stderr и переводит строку (добавляет символ'\n').
Библиотека
Библиотека представлена модулем std/.
while(initial: any, checker: closure(result: any): bool, handler: closure(result: any): any): any;list/— модуль для работы со списками:generate(initial: any, number: num, generator: closure(result: any): any): list<any>;generate_if(initial: any, checker: closure(result: any): bool, generator: closure(result: any): any): list<any>;for_each(list: list<any>, handler: closure(item: any): nil): nil;map(list: list<any>, handler: closure(item: any): any): list<any>;filter(list: list<any>, filter: closure(item: any): bool): list<any>;reduce(initial: any, list: list<any>, handler: closure(result: any, item: any): any): any;zip(list_i: list<any>, list_ii: list<any>, handler: closure(item_i: any, item_ii: any): any): list<any>;zip_longest(list_i: list<any>, list_ii: list<any>, handler: closure(item_i: any, item_ii: any): any): list<any>;reverse(list: list<any>): list<any>;last(list: list<any>): any;init(list: list<any>): nil|list<any>;find(list: list<any>, comparator: closure(item: any): bool): nil|num;find_last(list: list<any>, comparator: closure(item: any): bool): nil|num;take(number: num, list: list<any>): list<any>;drop(number: num, list: list<any>): list<any>;sort(list: list<any>, lesser: closure(item_i: any, item_ii: any): bool): list<any>;
cli/— модуль для работы с CLI:ansi(name: str, text: str): str— возвращает строкуtext, обёрнутую в управляющую последовательность ANSI; выбор конкретной последовательности осуществляется на основе имениname:- стили:
"bold";"italic";"underline";"strikethrough";
- цвета:
"black";"red";"green";"yellow";"blue";"magenta";"cyan";"white";
- стили:
test/— модуль для юнит-тестирования:test(name: str, test: closure(): bool): bool;group(name: str, tests: closure(): list<bool>): list<bool>(переменная окруженияTEST_SEPARATOR_LENGTHзадаёт ширину разделителей групп; по умолчанию: 80).