Функции для работы с генерацией кода
Во время выполнения вычислений можно сгенерировать код, состоящий из узлов S-expressions. Для этого используется механизм представления кода, упакованного в ресурс. После конструирования кода можно подставить его в основную програму с помощью функции EvaluateCode. Для отладки сконвертировать код в строку можно с помощью функции FormatCode.
Возможные типы узлов в S-expressions, которые можно использовать для генерации кода:
- Атом - нетипизированная строка из нуля и более символов.
- Список - последовательность из нуля и более узлов. Соответствует типу
кортеж
в SQL. - Вызов встроенной функции - состоит из имени, выраженного атомом, и последовательности из нуля и более узлов, которые являются аргументами этой функции.
- Объявление лямбда функции - состоит из объявления имен аргументов и узла, который является корнем тела этой лямбда функции.
- Аргумент лямбды функции - узел, который может использоваться только внутри тела лямбда-функции.
- Мир - специальный узел, маркирующий операции ввода/вывода.
Узлы S-expressions образуют ориентированный граф. При этом атомы - всегда листовые узлы, так как не могут содержать дочерних узлов.
В текстовой записи S-expressions записываются следующим образом:
- Атом -
'"foo"
. Символ апострофа (') является признаком цитирования последующей строки, обычно заключенной в кавычки. - Список -
'("foo" "bar")
. Символ апострофа (') является признаком того, что в скобках не будет вызова функции. - Вызов встроенной функции -
(foo "bar")
. Первый элемент внутри скобок - обязательное имя функции, а далее указываются ее аргументы. - Объявление лямбда функции -
(lambda '(x y) (+ x y))
. После ключевого словаlambda
стоит список из имен аргументов, за которым следует тело лямбда функции. - Аргумент лямбда функции -
x
. В отличие от атома, строка без символа апострофа (') является ссылкой на имя в текущей области видимости. При объявлении лямбда функции в область видимости тела добавляются имена аргументов, причем при необходимости скрывается имя из объемлющей области видимости. - Мир -
world
.
FormatCode
Сериализация кода в виде S-expressions. Код не должен содержать свободных аргументов функций, т.е. для сериализации кода лямбда функции нужно передавать ее целиком, а не выражения, потенциально содержащие аргументы лямбда функции.
Примеры
SELECT FormatCode(AtomCode("foo"));
-- (
-- (return '"foo")
-- )
WorldCode
Построить узел кода с типом мир
.
Примеры
SELECT FormatCode(WorldCode());
-- (
-- (return world)
-- )
AtomCode
Построить узел кода с типом атом
из строки, переданной в аргумент.
Примеры
SELECT FormatCode(AtomCode("foo"));
-- (
-- (return '"foo")
-- )
ListCode
Построить узел кода с типом список
из набора узлов или списков узлов кода, переданных в аргументы. При этом списки из аргументов встраиваются как отдельно перечисленные узлы кода.
Примеры
SELECT FormatCode(ListCode(
AtomCode("foo"),
AtomCode("bar")));
-- (
-- (return '('"foo" '"bar"))
-- );
SELECT FormatCode(ListCode(AsList(
AtomCode("foo"),
AtomCode("bar"))));
-- (
-- (return '('"foo" '"bar"))
-- )
FuncCode
Построить узел кода с типом вызов встроенной функции
из строки с именем функции и набора узлов или списков узлов кода, переданных в аргументы. При этом списки из аргументов встраиваются как отдельно перечисленные узлы кода.
Примеры
SELECT FormatCode(FuncCode(
"Baz",
AtomCode("foo"),
AtomCode("bar")));
-- (
-- (return (Baz '"foo" '"bar"))
-- )
SELECT FormatCode(FuncCode(
"Baz",
AsList(
AtomCode("foo"),
AtomCode("bar"))));
-- (
-- (return (Baz '"foo" '"bar"))
-- )
LambdaCode
Построить узел кода с типом объявление лямбда функции
можно из:
- Лямбда функции, если заранее известно количество аргументов. В этом случае в качестве аргументов этой лямбда функции будут переданы узлы типа
аргумент
. - Количества аргументов и лямбда функции с одним аргументом. В этом случае в качестве аргумента этой лямбды функции будет передан список узлов типа
аргумент
.
Примеры
SELECT FormatCode(LambdaCode(($x, $y) -> {
RETURN FuncCode("+", $x, $y);
}));
-- (
-- (return (lambda '($1 $2) (+ $1 $2)))
-- )
SELECT FormatCode(LambdaCode(2, ($args) -> {
RETURN FuncCode("*", Unwrap($args[0]), Unwrap($args[1]));
}));
-- (
-- (return (lambda '($1 $2) (* $1 $2)))
-- )
EvaluateCode
Подстановка в основную программу узла кода, переданного в аргумент.
Примеры
SELECT EvaluateCode(FuncCode("Int32", AtomCode("1"))); -- 1
$lambda = EvaluateCode(LambdaCode(($x, $y) -> {
RETURN FuncCode("+", $x, $y);
}));
SELECT $lambda(1, 2); -- 3
ReprCode
Подстановка в основную программу узла кода, который является представлением результата вычисления выражения, переданного в аргумент.
Примеры
$add3 = EvaluateCode(LambdaCode(($x) -> {
RETURN FuncCode("+", $x, ReprCode(1 + 2));
}));
SELECT $add3(1); -- 4
QuoteCode
Подстановка в основную программу узла кода, который является представлением выражения или лямбда функции, переданной в аргумент. Если во время подстановки были найдены свободные аргументы лямбда функций, то они вычисляются и подставляются в код как в функции ReprCode.
Примеры
$lambda = ($x, $y) -> { RETURN $x + $y };
$makeClosure = ($y) -> {
RETURN EvaluateCode(LambdaCode(($x) -> {
RETURN FuncCode("Apply", QuoteCode($lambda), $x, ReprCode($y))
}))
};
$closure = $makeClosure(2);
SELECT $closure(1); -- 3