Смекни!
smekni.com

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

> module () error Mod_1 end module; Error, (in unknown) Mod_1 > Chap:= module () error Mod_2 end module; Error, (in unknown) Mod_2

> module Art () error Mod_3 end module; Error, (in Art) Mod_3

> A:= module B () end module:

> type(A, `module`), type(B, `module`); ⇒ true, true > A:= module B () end module;

Error, (in B) attempting to assign to `B` which is protected

С учетом сказанного данный фрагмент достаточно прозрачен и особых пояснений не требует. Между тем, предпоследний пример фрагмента иллюстрирует возможность одновременного именования модуля как первым, так и вторым способом. Тогда как уже повторная аналогичная попытка вызывает ошибочную ситуацию. Это связано с тем, что имя поименованного вторым способом модуля имеет protected-атрибут. Рассмотрим компоненты определения модуля несколько детальнее.

Ряд неудобств работы с программными модулями второго типа, которые в ряде случаев требуют более сложных алгоритмов их обработки при создании программного обеспечения с их использованием, поднимает задачу создания процедуры, конвертирующей их в модули первого типа. При этом, под программным модулем первого типа мы будем понимать модуль, именованный конструкцией вида “Name := module () … “, тогда как программный модуль второго типа характеризуется именующей конструкцией следующего вида “module Name () … “. Более того, имеется и третий способ именования программных модулей, позволяющий за одно определение задавать функционально эквивалентные разноименные модули второго типа, как это иллюстрирует следующий весьма простой фрагмент:

> M:= module M1 () export x; x:= () -> `+`(args)/nargs end module: 5*M:- x(64,59,39,17,10);

189

> map(type, [M, M1], `module`), map(type, [M, M1], 'mod1'); ⇒ [true, true], [false, false] > map(mod21, [M, M1]), map(type, [M, M1], 'mod1'), M:- x(59, 39), 3*M1:- x(64, 17, 10); [], [true, true], 49, 91

Некоторые полезные соображения по использованию программных модулей второго типа могут быть найдены в наших книгах [12-14,29-33,39,41,45,103]. Достаточно полезная процедура mod21 решает данную проблему конвертирования программных модулей. Ранее мы уже представляли ее аналог, реализованный нашим методом “дисковых транзитов”, здесь же была использована упоминаемая выше конструкция типа eval({parse|came}(<сгенерированная строка>)).

Вызов процедуры mod21(M) возвращает NULL-значение, т.е. ничего, обеспечивая в текущем сеансе конвертацию программного модуля второго типа, заданного фактическим аргументом M, в эквивалентный ему программный модуль первого типа с тем же самым именем. Если же вызов процедуры mod21(M,f) использует второй необязательный аргумент f, то процедура рассматривает его как каталог, в котором должен быть сохранен файл "M.mod1" с определением отконвертированного программного модуля М (если каталог f отсутствует, то он будет создан с произвольным уровнем вложенности). В этом случае вызов процедуры mod21 возвращает полный путь к файлу данных с сохраненным отконвертированным модулем М и с выводом соответствующего сообщения, информирующем о полном пути к созданному файлу. Файл с сохраненным программным модулем имеет входной Maple-формат. Примеры нижеследующего фрагмента достаточно прозрачно иллюстрируют сказанное.

mod21 := proc(M::`module`) local a b c d t p k v sf h, , , , , , , , , , ν; assign(a = convert(eval(M), 'string'), t = { }, p = [ ], sf = ((x y, ) → `if`(length( )y ≤ length( )x , true false, ))); assign(b = Search2(a, {"module "})), assign(' 'b = [seq(k + 5, k = b)]); assign(c = {seq(nexts(a, b[k], "() "), k = 1 .. nops(b))}); seq(assign(' 'p = [op(p), a[c k[ ][1] + 1 .. c k[ ][2] − 1]]), k = 1 .. nops( )c ), assign(' 'p = sort(p sf, )); p := [seq op( ([assign(' 'r = Search2(p k[ ], {":-"})), `if`(r ≠ [ ] and p k[ ] ≠ ":-", p k[ ][2 .. r[-1] + 1], `if`(p k[ ] = " ", NULL, cat(p k[ ][1 .. -2], ":-")))]), k = 1 .. nops(p))];

p := [seq(k = "", k = p)]; seq `if`( (2 < c k[ ][2] − c k[ ][1], assign(' 't = {op( )t , v $ (v = c k[ ][1] + 1 .. c k[ ][2] − 1)}), NULL), k = 1 .. nops( )c );

eval(parse(cat("unprotect(", M, "), assign('", M, "'=", SUB_S(p, dsps(a, t)), ")")))

; if nargs = 2 then if type(args 2[ ], 'dir') then h := cat(args 2[ ], "&bsol;", M, ".mod1"); save M h h, ; else assign(ν = interface(warnlevel)), null(interface(warnlevel = 0)), assign(' 'h = cat(MkDir args[2]( ), "&bsol;", M, ".mod1"));

(proc() null interface(( warnlevel = ν)); save M h, end proc )( ), h;

WARNING("module <%1> has been converted into the first type, an&bsol; d saved in datafile <%2>", M h, ) end if

end if

end proc

> restart; module A () local C; export B; B:=C[y](1,2,3)+C[z]: module C () local H; export y, z; y:=() -> sum(args[k],k=1..nargs); z:=H[h](6,7,8); module H () export h; h:=()->sqrt(`+`(args)) end module end module; end module: A1:=module () local C; export R; R:= C[y](1 ,2, 3) + C[z]: C:= module () local H; export y, z; y:= () -> sum(args[k], k=1 .. nargs); z:=H[h](6, 7, 8); H:= module () export h; h:= () -> `*`(args) end module end module; end module:

A2:=module () local C; export R; R:= C[y](1,2,3)+C[z]: module C () local H; export y, z; y:=() -> sum(args[k], k=1..nargs); z:=H[h](6, 7, 8); H:= module () export h; h:= () -> `*`(args) end module end module; end module: A3:= module A3 () export h; h:= () -> sum(args[k], k=1 .. nargs)/nargs end module:

Error, attempting to assign to `A3` which is protected

> M:= module M1 () export G; G:= () -> sum(args[k], k=1 .. nargs)/nargs end module: N:=module N1 () export Z; local M; Z:= () -> M:- h(args); M:= module () export h; h:= () -> sum(args[k], k=1 .. nargs)/nargs end module end module: mod21(A, "C:/temp/aaa/ccc"), mod21(A1,"C:/temp/aaa/ccc"), mod21(A2,"C:/temp/aaa/ccc"), mod21(A3,"C:/temp/aaa/ccc"), mod21(M,"C:/temp/aaa/ccc"), mod21(M1,"C:/temp/aaa/ccc"), mod21(N1,"C:/temp/aaa/ccc"), mod21(N, "C:/temp/aaa/ccc");

Warning, module <A> has been converted into the first type, and saved in datafile

<c:&bsol;temp&bsol;aaa&bsol;ccc&bsol;A.mod1>

"C:/temp/aaa/ccc&bsol;A1.mod1", "C:/temp/aaa/ccc&bsol;A2.mod1", "C:/temp/aaa/ccc&bsol;A3.mod1",

"C:/temp/aaa/ccc&bsol;M.mod1", "C:/temp/aaa/ccc&bsol;M1.mod1", "C:/temp/aaa/ccc&bsol;N1.mod1",

"C:/temp/aaa/ccc&bsol;N.mod1"

> map(type, [A, A1, A2, A3, M, M1, N, N1], 'mod1');

[true, true, true, true, true, true, true, true]

Следует отметить, что именно на данной процедуре мы обнаружили недостатки работы пакетного стэка и нам пришлось редактировать соответствующим образом процедуру, чтобы обеспечить совместимость в рамках Maple релизов 6-10. Вопросы работы с модулями обоих типов, а также соответствующие для этого средства рассмотрены в наших книгах [12-14,41,42,45,103].

Декларация description. Определение программного модуля может содержать декларацию description, включающую текстовую строку, являющуюся своего рода кратким документированием данного модуля. Например, строка может содержать краткое описание модуля. Данная компонента определения модуля аналогична одноименной компоненте описания процедуры и в результате автоматического упрощения модуля становится самой последней среди всех его деклараций. Декларация определяет одну либо несколько строк, составляющих единое описание модуля. Следующий весьма простой фрагмент иллюстрирует сказанное.

> GRSU:= module()

export Sr; local k;

description "Sr - средняя аргументов";

Sr:= () -> `+`(args)/nargs;

end module;

GRSU := module () local k; export Sr; description "Sr - средняя аргументов "; end module

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

Декларация options. Определение программного модуля может содержать подобно случая процедуры опции, определяющие режим работы с модулем. Однако, в отличие от процедур опции remember, system, arrow, operator и inline не имеют смысла. Опции кодируются или в форме переменной, или уравнения с переменной в качестве его левой части. Если в options-декларации указаны нераспознаваемые языком опции, то они игнорируются, что позволяет пользователю указывать опции для собственных нужд, которые распознаются языком как атрибуты.

Из опций модуль допускает trace, package и `Copyright …`, аналогичные случаю Mapleпроцедур [12], и специальные опции load = name и unload= name, где name – имя локальной или экспортируемой переменной модуля, определяющей процедуру. Данная процедура вызывается при первоначальном создании модуля или при чтении его из системы хранения функциональных средств пакета. Как правило, данная опция используется для какой-либо инициализационной цели модуля. Следующий простой фрагмент иллюстрирует применение load-опции для инициализации Sr-процедуры:

> module Q () local Sr; export Ds; options load=Sr; Ds:=() -> sqrt(sum((args[k]-Sr(args))^2, k = 1..nargs)/nargs); Sr:= () -> sum(args[k], k = 1..nargs)/nargs; end module:

> 6*Q:- Ds(39, 44, 10, 17, 64, 59); ⇒ 14249

Опция load позволяет создавать наборы тематически связанных экспортируемых процедур, для инициализации которых используются необходимые локальные неэкспортируемые процедуры и/или функции Данная опция выполняет своего рода инициализационные функции модуля. Опция unload = name определяет имя локальной либо экспортируемой процедуры модуля, которую следует вызвать, когда модуль более недоступен либо производится выход из пакета. Модули с опцией `package` понимаются системой как пакетные модули и их экспорты автоматически получают protected-атрибут. Более детально с опциями модуля можно ознакомиться в справке пакета по ?module,option.

Локальные и глобальные переменные ПМ. Аналогично процедурам, ПМ поддерживают механизм локальных (local) и глобальных (global) переменных, используемых в определении модуля. Глобальные переменные имеют областью определения текущий сеанс, тогда как область определения локальных переменных ограничивается самим модулем. Однако, в отличие от процедур, модуль поддерживает более гибкий механизм локальных переменных; при этом, недопустимо определение одной и той же переменной как в local-декларации, так и в export-декларации. Попытка подобного рода приводит к ошибочной ситуации. Результатом вычисления определения модуля является модуль, к экспортируемым членам (переменным) которого можно программно обращаться вне области модуля. Следующий простой фрагмент иллюстрирует результат определения локальных и глобальных переменных программного модуля:

> module() local a,b; global c; assign(a=64, b=59); c:= proc() `+`(args) end proc end module:

> a, b, c(42, 47, 89, 96, 67, 62); ⇒ a, b, 403

> N:= module() export d; d:= proc() `+`(args) end proc end module:

> d(64, 59, 39, 44, 10, 17), N: -d(64, 59, 39, 44, 10, 17); ⇒ d(64, 59, 39, 44, 10, 17), 233