ksi
Язык программирования
Пример hello world
@main
.do (
'Hello' write_line@std{}
)
Результат:
Hello
Комментарии
-- В начале файла желательно
-- прокомментировать его назначение
@main -- Главный модуль
/*
Пространство модуля
*/
.do (
-- Локальное пространво
-- Раздел .do не обязателен для каждого модуля
)
/*
Продолжение пространства модуля
-- Комментарии не выполняются системой
/* Они для облегчения понимания */
*/
Пространство модуля
@shop
fruit := 'Apple' -- Константа
price = 5 -- Переменная
Раздел .do
@main
dice = range@std(1 6)
.do (
.local ( result = dice random@std{} )
result write_line@std{}
)
Возможный результат:
5
Виды значений
Конструкторы видов - это команды, которые создают новые типы данных. Типы и функции в ksi являются значениями ячейки.
Команды:
.fn
.struct
.enum
Функция
@main
squared := .fn (x) .seq (
ret = x * x
)
.do (
-- Обычный вызов функции:
squared(3) write_line@std{}
-- Цепной вызов функции:
5 squared{} write_line@std{}
)
Результат:
9
25
squared ~ константа, хранящая указатель на функцию
x ~ параметр функции
.seq ~ список действий (sequence)
ret ~ ячейка результата
Структура данных
@sample
coords := .struct (x y)
origin = coords(0 0)
.do (
point = coords(3 4)
point distance{} write_line@std{}
)
distance := .fn (from, to = origin) .seq (
ret = (to.x - from.x) ^ 2
ret += (to.y - from.y) ^ 2
ret = root@std(ret, 2)
)
Результат:
5
Встраивание структур, перегрузка функций
@main
coords = .struct ( x y )
square = .struct (
.insert ( coords )
width
) -- x y width
rectangle = .struct (
.insert ( square )
height
) -- x y width height
scale[square] = .fn (ret, factor) .seq (
ret.width *= factor
)
scale[rectangle] = .fn (ret, factor) .seq (
-- scale only width property first:
ret->square scale{factor}
-- scale the height too:
ret.height *= factor
)
.do (
.local ( shape = rectangle(0 0, 10 20) )
shape scale{0.5}
shape area{} write_line@std{} -- 50
-- Площадь фигуры, если бы это был квадрат:
shape->square area{} write_line@std{} -- 25
)
area[square] = .fn (shape) .seq (
ret = shape.width ^ 2
)
area[rectangle] = .fn (shape) .seq (
ret = shape.width * shape.height
)
Результат:
50
25
В языке ksi нет наследования структур.
Вместо этого используется встраивание свойств одной структуры в другую структуру через команду .insert
Оператор стрелка -> служит для создания срезов объекта. Справа от этого оператора указывается встроенный тип - составляющая структура, по которой делается срез объекта.
Функция scale() является функцией‑модификатором. Она возвращает свой первый параметр с именем ret
Функция area() вычисляет площадь фигуры, и она перегружена для типов square и rectangle.
Упрощённо говоря перегрузка функции - это переменная, хранящая ассоциативный массив $map, где ключом служит тип первого параметра функции, а значением - сама функция конкретной перегрузки.
Перечисление
@sample
align_type := .enum (
left center right
)
.do (
node_align = align_type.left
write_line@std(node_align.name)
-- Печать элементов перечисления
align_type elements@std .each it (
it write_line@std{
key_separator: ': '
separator: "\n"
}
write_line@std()
)
)
@std
/*
enum_element := .struct (
index
name
)
*/
Результат:
left
index: 0
name: left
index: 1
name: center
index: 2
name: right
Циклы
Цикл .each для массива
@main
numbers = [3 2 1] -- array
.do (
numbers
reverse@std{}
.each item (
item write_line@std{}
)
)
Результат:
1
2
3
reverse@std ~ Генератор выдачи новой последовательности.
reverse_it@std ~ Функция, которая меняет исходную последовательность.
Цикл .each для диапазона
@main
range = range@std(1 3)
.do (
.local (row cell)
-- Таблица умножения чисел от 1 до 3
range .for .each row (
range .for .each cell (
.seq (" ", row * cell)
write@std{}
)
write_line@std()
)
)
Результат:
1 2 3
2 4 6
3 6 9
У команды .for есть параметр шага.
.for(step: 0.5)
.leave_scope ~ Выход из цикла
.leave_scope[depth: 2]