1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
# Функции для работы с генерацией кода
Во время выполнения вычислений можно сгенерировать код, состоящий из узлов [S-expressions](/docs/s_expressions). Для этого используется механизм представления кода, упакованного в [ресурс](../types/special.md). После конструирования кода можно подставить его в основную програму с помощью функции [EvaluateCode](#evaluatecode). Для отладки сконвертировать код в строку можно с помощью функции [FormatCode](#formatcode).
Возможные типы узлов в S-expressions, которые можно использовать для генерации кода:
* Атом - нетипизированная строка из нуля и более символов.
* Список - последовательность из нуля и более узлов. Соответствует типу `кортеж` в SQL.
* Вызов встроенной функции - состоит из имени, выраженного атомом, и последовательности из нуля и более узлов, которые являются аргументами этой функции.
* Объявление лямбда функции - состоит из объявления имен аргументов и узла, который является корнем тела этой лямбда функции.
* Аргумент лямбды функции - узел, который может использоваться только внутри тела лямбда-функции.
* Мир - специальный узел, маркирующий операции ввода/вывода.
Узлы S-expressions образуют ориентированный граф. При этом атомы - всегда листовые узлы, так как не могут содержать дочерних узлов.
В текстовой записи S-expressions записываются следующим образом:
* Атом - `'"foo"`. Символ апострофа (') является признаком цитирования последующей строки, обычно заключенной в кавычки.
* Список - `'("foo" "bar")`. Символ апострофа (') является признаком того, что в скобках не будет вызова функции.
* Вызов встроенной функции - `(foo "bar")`. Первый элемент внутри скобок - обязательное имя функции, а далее указываются ее аргументы.
* Объявление лямбда функции - `(lambda '(x y) (+ x y))`. После ключевого слова `lambda` стоит список из имен аргументов, за которым следует тело лямбда функции.
* Аргумент лямбда функции - `x`. В отличие от атома, строка без символа апострофа (') является ссылкой на имя в текущей области видимости. При объявлении лямбда функции в область видимости тела добавляются имена аргументов, причем при необходимости скрывается имя из объемлющей области видимости.
* Мир - `world`.
## FormatCode
Сериализация кода в виде [S-expressions](/docs/s_expressions). Код не должен содержать свободных аргументов функций, т.е. для сериализации кода лямбда функции нужно передавать ее целиком, а не выражения, потенциально содержащие аргументы лямбда функции.
#### Примеры
```yql
SELECT FormatCode(AtomCode("foo"));
-- (
-- (return '"foo")
-- )
```
## WorldCode
Построить узел кода с типом `мир`.
#### Примеры
```yql
SELECT FormatCode(WorldCode());
-- (
-- (return world)
-- )
```
## AtomCode
Построить узел кода с типом `атом` из строки, переданной в аргумент.
#### Примеры
```yql
SELECT FormatCode(AtomCode("foo"));
-- (
-- (return '"foo")
-- )
```
## ListCode
Построить узел кода с типом `список` из набора узлов или списков узлов кода, переданных в аргументы. При этом списки из аргументов встраиваются как отдельно перечисленные узлы кода.
#### Примеры
```yql
SELECT FormatCode(ListCode(
AtomCode("foo"),
AtomCode("bar")));
-- (
-- (return '('"foo" '"bar"))
-- );
SELECT FormatCode(ListCode(AsList(
AtomCode("foo"),
AtomCode("bar"))));
-- (
-- (return '('"foo" '"bar"))
-- )
```
## FuncCode
Построить узел кода с типом `вызов встроенной функции` из строки с именем функции и набора узлов или списков узлов кода, переданных в аргументы. При этом списки из аргументов встраиваются как отдельно перечисленные узлы кода.
#### Примеры
```yql
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
Построить узел кода с типом `объявление лямбда функции` можно из:
* [Лямбда функции](../syntax/expressions.md#lambda), если заранее известно количество аргументов. В этом случае в качестве аргументов этой лямбда функции будут переданы узлы типа `аргумент`.
* Количества аргументов и [лямбда функции](../syntax/expressions.md#lambda) с одним аргументом. В этом случае в качестве аргумента этой лямбды функции будет передан список узлов типа `аргумент`.
#### Примеры
```yql
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
Подстановка в основную программу узла кода, переданного в аргумент.
#### Примеры
```yql
SELECT EvaluateCode(FuncCode("Int32", AtomCode("1"))); -- 1
$lambda = EvaluateCode(LambdaCode(($x, $y) -> {
RETURN FuncCode("+", $x, $y);
}));
SELECT $lambda(1, 2); -- 3
```
## ReprCode
Подстановка в основную программу узла кода, который является представлением результата вычисления выражения, переданного в аргумент.
#### Примеры
```yql
$add3 = EvaluateCode(LambdaCode(($x) -> {
RETURN FuncCode("+", $x, ReprCode(1 + 2));
}));
SELECT $add3(1); -- 4
```
## QuoteCode
Подстановка в основную программу узла кода, который является представлением выражения или [лямбда функции](../syntax/expressions.md#lambda), переданной в аргумент. Если во время подстановки были найдены свободные аргументы лямбда функций, то они вычисляются и подставляются в код как в функции [ReprCode](#reprcode).
#### Примеры
```yql
$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
```
|