Язык программирования
Виды значений
Конструкторы видов - это команды, которые создают новые функции и типы данных. Типы и функции в ksi могут быть значениями ячейки.
Команды:
.fn ~ Функция
.struct ~ Структура
.enum ~ Перечисление
Функция
@main
-- Возведение в квадрат
squared = .fn (x) .seq (
ret = x * x
)
.do (
squared(1) write_line@std{}
-- Обычный вызов функции:
write_line@std( squared(3) )
-- Цепной вызов функции:
5 squared{} write_line@std{}
)
Результат:
1
9
25
В этом примере:
squared ~ константа, хранящая указатель на функцию
x ~ параметр функции
.seq ~ список действий (sequence)
ret ~ ячейка результата
Структура данных
Структура - это тип. Создание экземпляра структуры аналогично вызову функции.
@main
coords = .struct (x y)
/*
указанные свойства структуры coords
при создании объекта
становятся свойствами экземпляра
*/
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
Встраивание структур, перегрузка функций
Вместо наследования структур в языке ksi используется встраивание свойств одной структуры в другую, через команду .insert . В скобках - список parent структур.
файл: data.insert.ksi
@main
coords = .struct ( x y )
-- У квадрата координаты и ширина
square = .struct (
.insert ( coords )
width
) -- свойства: x y width
-- прямоугольник
rectangle = .struct (
.insert ( square )
height
) -- x y width height
файл: functions.overloading.ksi
@main
-- Масштабирование квадрата
scale[square] = .fn (ret, factor) .seq (
ret.width *= factor
)
-- Масштабирование прямоугольника
scale[rectangle] = .fn (ret, factor) .seq (
ret.width *= factor
ret.height *= factor
)
файл: main.do.ksi
@main
.do (
.var shape = rectangle(0 0, 10 20)
-- уменьшаем в 2 раза:
shape scale{0.5}
-- Функция area() определена ниже
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
Оператор стрелка -> выдаёт под-объект. Перед этим оператором ставится ячейка, хранящая исходный объект. А после - указывается parent тип, указанный в .insert . У под-объекта общие свойства с исходным.
В этом примере функция scale() является функцией‑модификатором, ведь имя её первого параметра ret - ячейка результата.
scale() и area() перегружены для разных типов.
Упрощённо говоря перегрузка функции - это ассоциативный массив $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 .var it (
it.val write_line@std{
key_separator: ': '
separator: "\n"
}
write_line@std()
)
)
Результат:
left
index: 0
name: left
index: 1
name: center
index: 2
name: right
Некоторые системные типы
/*
-- псевдокод --
@global
$range := .struct (
from
to
)
$iterator := .struct (
pos -- position
key
val -- value
)
$enum_element := .struct (
index
name
value
)
$cmp := .enum (
less = -1
equal = 0
greater = +1
)
*/
Читать далее: управляющие команды ›