Next: , Previous: Функции, Up: Определение функций   [Contents][Index]

37.3 Макросы

Функция: buildq (L, expr)

Подставляет значения переменных, определяемых списком L, в выражение expr параллельно без перевычисления expr. Результирующее выражение упрощается, но не вычисляется после выполнения buildq.

Элементы списка L являются символами или операторами присваивания symbol: value, вычисляемые параллельно. Т.е. значение переменных в правой части присваиваний вычисляются в контексте, в котором вызван buildq, но не в контексте списка присваиваний L. Если для некоторых переменных в списке L не задано значений, то для них сохраняются значения из контекста вызова buildq.

Переменные из списка L подставляются в expr параллельно. Т.е. значение каждой подстановки определяется до подстановки, и одна переменная не оказывает никакого влияния на другую.

Если переменная x присутствует в expr в виде splice (x), то x должна иметь значение в форме списка, и этот список будет вместо подстановки интерполирован в expr.

Любые другие переменные в expr, не присутствующие в L, переносятся в результат буквально без изменения, даже в том случае, когда имеют значение в контексте вызова buildq.

Примеры:

Переменной a явно присвоено значение x, тогда как b имеет значение (а именно 29) из контекста вызова, а c сохраняется неизменным. Результат остается невычисленным до явного применения ''%.

(%i1) (a: 17, b: 29, c: 1729)$
(%i2) buildq ([a: x, b], a + b + c);
(%o2)                      x + c + 29
(%i3) ''%;
(%o3)                       x + 1758

Переменная e равна списку, который подставляется в foo и интерполируется в bar.

(%i1) buildq ([e: [a, b, c]], foo (x, e, y));
(%o1)                 foo(x, [a, b, c], y)
(%i2) buildq ([e: [a, b, c]], bar (x, splice (e), y));
(%o2)                  bar(x, a, b, c, y)

Результат подстановки упрощается. Если бы упрощение выполнилось до подстановки, то нижеследующие результаты совпали бы.

(%i1) buildq ([e: [a, b, c]], splice (e) + splice (e));
(%o1)                    2 c + 2 b + 2 a
(%i2) buildq ([e: [a, b, c]], 2 * splice (e));
(%o2)                        2 a b c

Значения переменных в L присваиваются параллельно, при последовательном присваивании первый результат был бы равен foo (b, b). Подстановки осуществляются параллельно. Сравните второй результат с результатом функции subst, которая выполняет подстановки последовательно.

(%i1) buildq ([a: b, b: a], foo (a, b));
(%o1)                       foo(b, a)
(%i2) buildq ([u: v, v: w, w: x, x: y, y: z, z: u],
              bar (u, v, w, x, y, z));
(%o2)                 bar(v, w, x, y, z, u)
(%i3) subst ([u=v, v=w, w=x, x=y, y=z, z=u],
             bar (u, v, w, x, y, z));
(%o3)                 bar(u, u, u, u, u, u)

Составим список уравнений с переменными в левой части и со значениями этих переменных в правой. Функция macroexpand выводит выражение, возвращаемое show_values.

(%i1) show_values ([L]) ::= buildq ([L], map ("=", 'L, L));
(%o1)   show_values([L]) ::= buildq([L], map("=", 'L, L))
(%i2) (a: 17, b: 29, c: 1729)$
(%i3) show_values (a, b, c - a - b);
(%o3)          [a = 17, b = 29, c - b - a = 1683]
(%i4) macroexpand (show_values (a, b, c - a - b));
(%o4)    map(=, '([a, b, c - b - a]), [a, b, c - b - a])

Используя функцию нескольких аргументов, создадим другую функцию, у которой некоторые аргументы имеют фиксированное значение.

(%i1) curry (f, [a]) :=
        buildq ([f, a], lambda ([[x]], apply (f, append (a, x))))$
(%i2) by3 : curry ("*", 3);
(%o2)        lambda([[x]], apply(*, append([3], x)))
(%i3) by3 (a + b);
(%o3)                       3 (b + a)
Функция: macroexpand (expr)

Если expr является вызовом макро-функции, то macroexpand возвращает макро-расширение expr без его вычисления. В противном случае, macroexpand возвращает expr.

Если макро-расширение expr само является макро-вызовом, то оно тоже раскрывается.

Функция macroexpand не вычисляет свои аргументы. Но если раскрытие макро-функций приводит к побочным эффектам, то эти эффекты выполняются.

См. также ::=, macros и macroexpand1.

Примеры

(%i1) g (x) ::= x / 99;
                                    x
(%o1)                      g(x) ::= --
                                    99
(%i2) h (x) ::= buildq ([x], g (x - a));
(%o2)            h(x) ::= buildq([x], g(x - a))
(%i3) a: 1234;
(%o3)                         1234
(%i4) macroexpand (h (y));
                              y - a
(%o4)                         -----
                               99
(%i5) h (y);
                            y - 1234
(%o5)                       --------
                               99
Функция: macroexpand1 (expr)

Если expr является вызовом макро-функции, то macroexpand1 возвращает макро-расширение expr без его вычисления. В противном случае, macroexpand1 возвращает expr.

Функция macroexpand1 не вычисляет свои аргументы. Но если раскрытие макро-функций приводит к побочным эффектам, то эти эффекты выполняются.

Если макро-расширение expr само является макро-вызовом, то оно не раскрывается.

См. также ::=, macros и macroexpand.

Примеры:

(%i1) g (x) ::= x / 99;
                                    x
(%o1)                      g(x) ::= --
                                    99
(%i2) h (x) ::= buildq ([x], g (x - a));
(%o2)            h(x) ::= buildq([x], g(x - a))
(%i3) a: 1234;
(%o3)                         1234
(%i4) macroexpand1 (h (y));
(%o4)                       g(y - a)
(%i5) h (y);
                            y - 1234
(%o5)                       --------
                               99
Глобальная переменная: macros

Значение по умолчанию: []

macros есть список всех определенных пользователем макро-функций. Оператор определения макро-функции ::= добавляет новую макро-функцию к этому списку, а kill, remove и remfunction удаляют ее из него.

См.также infolists.

Функция: splice (a)

Интерполирует список, обозначенный атомом a в выражение, но только если splice присутствует внутри buildq. В противном случае splice рассматривается как неопределенная функция. Если переменная a присутствует внутри buildq сама по себе без splice, то вместо a подставляется (не интерполируется) соответствующий список. Аргументом splice может быть только атом, но не явный список или выражение, дающее список в качестве значения.

Обычно, splice применяется для задания аргументов функции или оператора. Для функции f, выражение f (splice (a)) внутри buildq преобразуется в f (a[1], a[2], a[3], ...). Для оператора o, выражение "o" (splice (a) внутри buildq преобразуется в "o" (a[1], a[2], a[3], ...), где o может быть оператором любого вида (обычно оператором с многими аргументами). Обратите внимание, что оператор должен быть заключен в двойные кавычки ".

Примеры:

(%i1) buildq ([x: [1, %pi, z - y]], foo (splice (x)) / length (x));
                       foo(1, %pi, z - y)
(%o1)                -----------------------
                     length([1, %pi, z - y])
(%i2) buildq ([x: [1, %pi]], "/" (splice (x)));
                                1
(%o2)                          ---
                               %pi
(%i3) matchfix ("<>", "<>");
(%o3)                          <>
(%i4) buildq ([x: [1, %pi, z - y]], "<>" (splice (x)));
(%o4)                   <>1, %pi, z - y<>

Next: , Previous: Функции, Up: Определение функций   [Contents][Index]