Смекни!
smekni.com

Программирование и разработка приложений в Maple (стр. 46 из 135)

возвращающие соответственно значения 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-процедуры имеет следующий простой вид, из которого довольно просто при необходимости извлекать ранее полученные значения вызовов процедуры: