Смекни!
smekni.com

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

> module() local a,b; export a,b,c; assign(a=64, b=59); c:=proc() nargs end proc end module; Error, export and local `a` have the same name

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

<Имя модуля>:- <Экспортируемая переменная>{(Фактические аргументы)}

<Имя модуля>[ <Экспортируемая переменная>]{(Фактические аргументы)} Это так называемый связывающий формат обращения к экспортируемым переменным модуля. По вызову встроенной функции exports(M) возвращается последовательность всех экспортов модуля М, тогда как по вызову процедуры with(M) возвращается список всех экспортов модуля М; при этом, во втором случае экспорты модуля М становятся доступными в текущем сеансе и к ним можно обращаться без ссылок на содержащий их модуль, как это иллюстрирует следующий простой фрагмент:

> M:= module() local k; export Dis, Sr; Dis:= () -> sqrt(sum((args[k] - Sr(args))^2, k=1..nargs)/ nargs); Sr:= () -> sum(args[k], k=1..nargs)/nargs; end module: exports(M),

[eval(Dis), eval(Sr)]; ⇒ Dis, Sr, [Dis, Sr]

> 5*M[Sr](64, 59, 39, 10, 17), 5*M[Dis](64, 59, 39, 10, 17); ⇒ 189, 11714

> 5*M:- Dis(64, 59, 39, 10, 17), with(M); ⇒ 11714 [, Dis Sr, ] > 5*Sr(64, 59, 39, 10, 17), 5*Dis(64, 59, 39, 10, 17); ⇒ 189, 11714

> G:= module() global X; export Y; Y:=() -> `+`(args)/nargs; X:=64 end module:

> X, Y(1, 2, 3), G:- Y(1, 2, 3); ⇒ 64, Y(1, 2, 3), 2

> V:= module() global Y; Y:=() -> `+`(args)/nargs end module;

V := module () global Y; end module

> V1:= proc() `+`(args)/nargs end proc: Y(1, 2, 3, 4, 5, 6, 7), V1(1, 2, 3, 4, 5, 6, 7); ⇒ 4, 4

Фрагмент представляет модуль М с двумя экспортами Dis и Sr. По вызову exports(M) получаем последовательность всех экспортов модуля М, однако это только имена. Затем по (:-)-связке получаем доступ к экспорту Dis с передачей ему фактических аргументов. Наконец, по вызову with(M) получаем список всех экспортов модуля М, определяя их доступными в текущем сеансе. Таким образом, глобальность той или иной переменной модуля можно определять или через global-декларацию, или через export-декларацию модуля. Однако, если в первом случае мы к такой переменной можем обращаться непосредственно после вычисления определения модуля, то во втором случае мы должны использовать (:-)-связку или вызов формата M[<Экспорт>]{(Аргументы)}. Наконец, модуль V и процедура V1 иллюстрируют функциональную эквивалентность обоих объектов – модульного и процедурного с тем лишь отличием, что модуль V позволяет «скрывать» свое тело в отличие от V1-процедуры. Таким образом, можно создавать модули без экспортов, возвраты которых обеспечиваются через их глобальные переменные, что обеспечивает скрытие внутреннего механизма вычислений. Однако, при сохранении такого модуля в Maple-библиотеке (пакетной или пользовательской) последующий доступ к его глобальным переменным стандартными средствами становится невозможным, т. е. указанный прием работает лишь при условии вычисления определения модуля в текущем сеансе. Следовательно, описанный выше прием достаточно искусственен и ограничен, и носит в основе своей лишь иллюстративный характер.

Как уже отмечалось, минимальным объектом, распознаваемым пакетом в качестве модуля, является определение одного из следующих видов:

M:= module() end module или module M1 () end module о чем говорит и их тестирование, а именно:

> restart; M:= module() end module: module M1 () end module:

> map(type, [M, M1], `module`), map(whattype, map(eval, [M, M1]));

[true, true], [module, module]

Тогда как попытка получить их экспорты посредством вызова with-процедуры вызывает ошибочную ситуацию со следующей релизо-зависимой диагностикой:

> M:= module () end module: module M1 () end module:

> with(M); Maple 6 - 8

Error, (in pacman:-with) module `M` has no exports > with(M1);

Error, (in pacman:-with) module `M1` has no exports

> with(M); Maple 9 - 10 Error, (in with) module `M` has no exports > with(M1);

Error, (in with) module `M1` has no exports

> lasterror; ⇒ "module `%1` has no exports" Maple 6 - 10 > map(exports, [M, M1]); ⇒ []

Тогда как во всех релизах переменная lasterror получает идентичное значение. Поэтому для обеспечения более простой работы с программными модулями рекомендуется для получения их экспортов использовать встроенную функцию exports, как иллюстрирует последний пример фрагмента, либо использовать нашу процедуру [103], которая является расширением стандартной процедуры with и которая не только в данной ситуации возвращает корректный результат, но и позволяет использовать себя внутри процедур в отличие от with, например:

With := proc(P::{`module`, package }, F::symbol) local a b c h, , , ; if nargs = 0 then error "'With' uses at least the 1st argument, which is missing" else assign(a = interface(warnlevel), b = cat([libname][1], "/_$Art17_Kr9$_")) , interface(warnlevel = 0) end if; if nargs = 1 then try c := with args( ) catch "module `%1` has no exports": return [ ] end try ; h := cat cat seq cat "unprotect(`"( ( ( ( , ,k "`):`", ,k "`:=eval(`" args[1] "`[`", , , ,k

"`]):protect(`", ,k "`):"), k = c)) 1[ .. -2], ":")

else h := cat(cat(seq(cat("unprotect(`", args[k], "`):`", args[k], "`:=eval(`", args 1[ ], "`[`" args[ ], k , "`]):protect(`" args[ ], k , "`):"), k = 2 .. nargs)) 1[ .. -2],

":") end if;

writeline(b h, ), close(b);

(proc() read b end proc )( ), null(interface(warnlevel = a)), fremove(b),

`if`(1 < nargs [, args 2 .. -1[ ]], c)

end proc

> With(M), With(M1); ⇒ [], []

Это обстоятельство следует учитывать при работе с модулями в программном режиме.

Так как модули, как правило, содержат процедуры, а те и другие поддерживают механизм локальных переменных, то при наличии неявно определенных локальных переменных язык при выводе об этом предупреждений привязывает их к содержащим их объектам, как это иллюстрирует следующий достаточно простой фрагмент:

> GRSU:= module() local a; export b; global t; a:= proc() c:= 64; h:= 10 end proc; b:= proc() d:= 17 end proc end module:

Warning, `c` is implicitly declared local to procedure `a`

Warning, `h` is implicitly declared local to procedure `a` Warning, `d` is implicitly declared local to procedure `b` > e:= proc() g:= 59 end proc: t:= proc() v:= 64 end proc:

Warning, `g` is implicitly declared local to procedure `e`

Warning, `v` is implicitly declared local to procedure `t`

Декларация export определяет последовательность локальных имен объектов модуля, к которым возможен доступ извне модуля, т.е. определяет локальные переменные (присущие сугубо модулю и скрываемые от внешней среды) глобальными. В отличие от локальных экспортируемые переменные модуля не могут быть определены таковыми неявно. Их следует определять явно через export-декларацию. Важно помнить, что при экспортировании модулем неопределенной локальной переменной она не тождественна одноименной глобальной переменной текущего сеанса, что иллюстрирует следующий пример:

> module R() export VG; VG:= () -> `+`(args) end module: evalb(VG= R:- VG); ⇒ false > VG:= 64: VG, R:- VG(64, 59, 39, 10, 17); ⇒ 64, 189

Из примера видно, что экспортируемая неопределенная переменная не тождественна одноименной глобальной VG-переменной. Данное свойство модульного механизма языка пакета позволяет, в частности, определять в модуле одноименные с пакетными функциональные средства, но определяющие различные вычислительные алгоритмы, как это иллюстрирует следующий простой фрагмент (см. прилож. 6 [13]):

> GU:=module() local k; export ln; ln:=()->evalf(sum(log(args[k]),k=1..nargs)) end module:

> ln(42, 47, 67, 89, 96, 64);

Error, (in ln) expecting 1 argument, got 6

> GU[ln](42, 47, 67, 89, 96, 64); ⇒ 25.00437748

Данное свойство, в частности, достаточно полезно при создании собственных функций пользователя, подобных пакетным функциям, но отличающимися какими-либо особенностями. При этом, имеется хорошая возможность сохранять за ними пакетные имена.

Вне программного модуля обращение к экспортируемым переменным модуля производится по конструкциям следующего общего вида:

Имя_модуля:- Имя_экспортируемой_переменной{(Аргументы)}

Имя_модуля[Имя_экспортируемой_переменной]{(Аргументы)}

Более того, выполнение предложения with(Имя_модуля) позволяет обращаться ко всем экспортируемым переменным модуля только по их именам, делая их доступными в текущем сеансе для любого активного либо находящегося в очереди готовых документов, как это иллюстрирует следующий весьма простой фрагмент:

> Gr:= module () export a, b, c; assign(a= 42, b= 47, c= 67) end module:

> Gr:- a, Gr:- b, Gr:- c, a, b, c, with(Gr); ⇒ 42, 47, 67, a, b, c, [a, b, c] > a, b, c; ⇒ 42, 47, 67

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

Каждое определение Maple-процедуры ассоциируется с неявными переменными args, nargs и procname, рассмотренными выше. Тогда как с определением ПМ ассоциируется только одна неявная thismodule-переменная. В рамках тела модуля данной переменной присваивается содержащий ее модуль. Это позволяет ссылаться на модуль в рамках его собственного определения. Следующий простой фрагмент иллюстрирует применение переменной thismodule:

> module AVGSv() export a, b; a:= () -> sum(args[k], k=1..nargs); b:= thismodule:- a(42, 47,

67, 62, 89, 96) end module: AVGSv:- a(64, 59, 39, 44, 17, 10), AVGSv:- b; ⇒ 233, 403 Посредством thismodule-переменной предоставляется возможность организации рекурсивных выполнений модуля внутри самого модуля, что существенно расширяет возможности модульного программирования в среде Maple-языка пакета.

По функции op можно получать доступ к трем компонентам модуля М, а именно: