возвращающие соответственно значения true и procedure, если Proc-объект является процедурой Maple, определенной любым из трех рассмотренных выше способов, и, кроме того, вычисленной. Следующий простой фрагмент иллюстрирует вышесказанное:
> O1:= proc() end proc: [type(O1, procedure),whattype(eval(O1))]; ⇒ [true, procedure] > O2:= () -> sum(args[k], k=1..nargs): [type(O2, 'procedure'), whattype(eval(O2))];
[true, procedure]
> define(O3, O3(x::anything, y) = x*y): [type(O3, 'procedure'), whattype(eval(O3))];
[true, procedure]
> Type_Proc:= proc(Id) `if`((type(Id, 'symbol') = true) and (whattype(eval(Id)) =
`procedure`), true, false) end proc: map(Type_Proc, [O1, O2, O3]); ⇒ [true, true, true]
В частности, последний пример фрагмента представляет простую тестирующую процедуру Type_Proc, возвращающую true-значение лишь тогда, когда объект, приписанный Id-идентификатору, является Maple-процедурой. При этом, еще раз следует обратить внимание на то обстоятельство, что корректное применение тестирующей процедуры whattype предполагает полное вычисление процедурного объекта, что обеспечивается использованием eval-функции, рассмотренной выше.
Так как программная структура процедуры вычисляется по специальным табличным правилам, то для полного доступа к ее элементам следует использовать eval-функцию, производящую полное вычисление процедуры, подобно тому, как она это делает для других структур, например массивов. По eval(Proc)-вызову возвращается определение процедуры, приписанное Proc-переменной, в качестве которой может выступать любой допустимый идентификатор. В связи со сказанным по whattype(Proc)-вызову возвращается symbol-значение, а по вызову whattype(eval(Proc)) – procedure-значение. Поэтому по op(n, eval(Proc))-вызову возвращается значение восьми компонент определения процедуры, приписаного Proc-переменной. В табл. 7 представлены n-значения для указанной конструкции и их смысловая нагрузка:
Таблица 7
n | По конструкции op(n, eval(Proc)) возвращается: |
1 | последовательность формальных аргументов Proc-процедуры |
2 | последовательность локальных переменных Proc-процедуры |
3 | последовательность параметров (опций) Proc-процедуры |
4 | содержимое remember-таблицы Proc-процедуры |
5 | содержимое description-секции Proc-процедуры |
6 | последовательность глобальных переменных Proc-процедуры |
7 | лексическая таблица |
8 | тип возвращаемого результата (если был определен) |
В случае отсутствия в определении процедуры какой-либо из рассмотренных секций на соответствующем ей n-значении конструкция op(n, eval(Proc)) возвращает NULL-значение. По nops(eval(Proc))-вызову всегда возвращается значение 8 (начиная с Maple 7) – максимально возможное число составляющих компонент определения Proc-процедуры. Вместе с тем, в число данных компонент не входит само тело процедуры и для возможности доступа к нему используется прием, рассматриваемый несколько ниже. Следующий достаточно прозрачный фрагмент иллюстрирует вышесказанное:
> IAN:= proc(x::float, y::integer, z::numeric) local k, h; global G,V,S; option `Copyright Tallinn Research Group * 29.03.99`, remember; description "G-average of arguments"; V*evalf(sum(args[k]^G, k= 1 .. 3)^(1/G))/S end proc; IAN:=proc (x::float, y::integer, z::numeric) description "G-average of arguments" ... end proc > G:= 59: V:= 64: S:= 39: [IAN(19.95, 59, 19.99), IAN(0.1, 17, 1.1)]; [96.82051282, 27.89743590] > for k to 8 do print(op(k, eval(IAN))) end do; x::float, y::integer, z::numeric k, h Copyright Tallinn Research Group * 29.03.99, remember table([(19.95, 59, 19.99) = 96.82051282, (0.1, 17, 1.1) = 27.89743590]) "G-average of arguments" G, V, S > proc() local k; option `Copyright * 29.03.99`; sum(args[k], k=1..nargs) end proc; % (64, 59, 39, 44, 17, 10); ⇒ proc() ... end proc 233 |
В приведенном фрагменте определяется простая IAN-процедура, содержащая все допустимые компоненты определения Maple-процедуры, и производится ее вычисление, выводящее на экран только частичный текст определения процедуры, ибо при ее определении был задействован Copyright-параметр option-секции. Однако, возвращаемое в результате вычисления определение является полным и его последующий вызов возвращает корректные результаты, как это иллюстрирует последний пример фрагмента с непоименованной процедурой. После вычисления определения производится двухкратный вызов процедуры; последующее использование op(k, eval(IAN))-конструкции в (for_do)предложении выводит содержимое всех восьми компонент IAN-процедуры.
Как следует из вышесказанного, тело процедуры рассмотренными средствами не идентифицируется в качестве ее компоненты и доступ к нему возможен иными средствами, рассматриваемыми несколько ниже. Здесь же уместно отметить лишь dismantle(P)-процедуру, обеспечивающую вывод структуры данных, определяемой P-выражением. Процедура выводит структуру P-выражения (которое для случая процедуры должно быть полностью вычисленным) в разрезе составляющих его подвыражений (компонент), их длины и относительные адреса в {десятичном|16-ричном|8-ричном} представлении. Следующий фрагмент иллюстрирует вывод структуры данных, отвечающей IAN-процедуре предыдущего примера:
> dismantle(eval(IAN));
PROC(9) #[`Copyright Tallinn Research Group * 29.03.99`, remember]
EXPSEQ(4)
DCOLON(3)
NAME(4): x
NAME(5): float #[protected]
DCOLON(3)
NAME(4): y
NAME(5): integer #[protected]
DCOLON(3)
NAME(4): z
NAME(5): numeric #[protected]
EXPSEQ(3)
NAME(4): k
NAME(4): h
EXPSEQ(3)
NAME(14): `Copyright Tallinn Research Group * 29.03.99`
NAME(6): remember
HASHTAB(129)
HASH(7)
EXPSEQ(4)
FLOAT(3): 19.95
INTPOS(2): 1995
INTNEG(2): -2
INTPOS(2): 59
FLOAT(3): 19.99
INTPOS(2): 1999
INTNEG(2): -2
FLOAT(3): 96.82051282
INTPOS(4): 9682051282
INTNEG(2): -8
HASH(7)
EXPSEQ(4)
FLOAT(3): .1
INTPOS(2): 1
INTNEG(2): -1
INTPOS(2): 17
FLOAT(3): 1.1
INTPOS(2): 11
INTNEG(2): -1
FLOAT(3): 27.89743590
INTPOS(4): 2789743590
INTNEG(2): -8
PROD(7)
NAME(4): V INTPOS(2): 1 FUNCTION(3) NAME(5): evalf #[protected] EXPSEQ(2) POWER(3) FUNCTION(3) NAME(4): sum #[protected, _syslib] EXPSEQ(3) POWER(3) TABLEREF(3) PARAM(2): [-1] EXPSEQ(2) LOCAL(2): [1] NAME(4): G EQUATION(3) LOCAL(2): [1] RANGE(3) INTPOS(2): 1 INTPOS(2): 3 PROD(3) NAME(4): G INTNEG(2): -1 INTPOS(2): 1 NAME(4): S INTNEG(2): -1 EXPSEQ(2) STRING(9): "G-average of arguments" EXPSEQ(4) NAME(4): G NAME(4): V NAME(4): S EXPSEQ(1) |
Данный фрагмент представляет внутреннюю структуру Maple-процедуры и на ее основе искушенный пользователь может решать целый ряд весьма интересных задач. Однако, в нашу задачу рассмотрение данной проблематики не входит. Здесь уже вполне можно вновь возвратиться к рассмотрению remember-параметра option-секции, предварительно дав дополнительную полезную информацию.
Набор из процедуры dismantle и 4-х функций assemble, addressof, disassemble и pointto известен как "хакерский" пакет в Maple. Последние четыре функции обеспечивают доступ к внутренним представлениям объектов Maple и к адресам, указывающим на них. Между тем, пользователь должен быть знаком с внутренним представлением объектов пакета перед использованием данного набора средств. Для этого рекомендуем обратиться, например, к руководствам [83,84]. Некоторые средства подобного типа представлены и в [41,42,103].
Для целого ряда типов процедур (и в первую очередь для рекурсивных), характеризуемых многократными вызовами на одних и тех же наборах фактических аргументов, важную задачу приобретает вопрос повышения эффективности их выполнения. Данная задача решается путем сохранения истории вызовов процедуры в текущем сеансе в специальной remember-таблице. Использование данного механизма требует определенных пространственных издержек, которые в ряде случаев могут быть катастрофическими, однако позволяют получать существенный временной выигрыш при различного рода циклических вычислениях на одинаковых значениях фактических аргументов процедур.
А именно, по remember-параметру с Proc-процедурой ассоциируется специальная таблица remember, которую можно получать по уже рассмотренной op(4, eval(Proc))-конструкции. Данная таблица аналогична обычной table-структуре, допуская те же средства обработки, что и последняя. Она содержит все вызовы процедуры, включая рекурсивные, в разрезе передаваемых значений фактических аргументов и возвращаемых на них процедурой значений (результатов вызовов). Данная таблица для произвольной Proc-процедуры имеет следующий простой вид, из которого довольно просто при необходимости извлекать ранее полученные значения вызовов процедуры: