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(plots, display, animate); ⇒ [display, animate] > display:= 59; Error, attempting to assign to `display` which is protected > animate:= 64; Error, attempting to assign to `animate` which is protected > Kr:=module() export sr, No; No:=() -> [[nargs], args]; sr:=() -> `+`(args)/nargs end module: > With(Kr, sr, No); ⇒ [sr, No] > No(1, 2, 3), sr(1, 2, 3); ⇒ [[3], 1, 2, 3], 2 > M:= module () end module: with(M); Error, (in with) module `M` has no exports > With(M); ⇒ [] |
Более того, при отсутствии у модуля М экспортов вызов with(M) вызывает ошибочную ситуацию с диагностикой "module `%1` has no exports" для всех релизов Maple. Поэтому для поддержки более удобной работы с экспортами модуля рекомендуется или использовать exports-функцию, возвращающую NULL-значение на модулях без экспортов, или нашу процедуру With, возвращающую в аналогичной ситуации пустой список, т.е. [].
Использование вызова процедуры with(P) для проверки экспортов пакетного модуля P не является целесообразным, ибо в этом случае производится загрузка в РОП всех его экспортов. Поэтому, для таких целей рекомендуется использовать процедуру tpacmod, имеющую формат вызова следующего вида: tpacmod(P {, Name}), где Р – имя пакетного модуля и Name – имя его экспорта [41,103]. Вызов процедуры с одним аргументом Р, в качестве которого допустимо только имя пакетного модуля, находящегося в Maple-библиотеке, логически сцепленной с главной библиотекой пакета, возвращает список экспортов модуля Р. Тогда как вызов процедуры tpacmod(P,Name) с двумя аргументами возвращает true, если Name является экспортом модуля Р, и false в противном случае. При этом, в любом случае экспорты модуля Р не загружаются в РОП и не становятся активными в текущем сеансе. Данная возможность весьма актуальна при работе с пакетными модулями. Следующий фрагмент представляет исходный текст процедуры tpacmod и примеры ее использования для проверки экспортов пакетных модулей.
> tpacmod:= proc(P::package) parse(cat("`if`(belong(Release(), 6 .. 8), `pacman`, `PackageManagement`):- ", convert(`if`(nargs=1,`pexports`,`pmember`)(`if`(nargs=1, args, op([args[2], args[1]]))), 'string')), 'statement') end proc; tpacmod := proc(P::package) parse cat("`if`(belong(Release(), 6 .. 8), `pacman`,( `PackageManagement`):- "convert `if`(, ( nargs = 1, pexports pmember, )( `if`(nargs = 1, args op, ([args 2[ ], args[1]]))), 'string')), 'statement') end proc > tpacmod(linalg); [BlockDiagonal, GramSchmidt, JordanBlock, LUdecomp, QRdecomp, Wronskian, addcol, addrow, adj, ==================================================================== swaprow, sylvester, toeplitz, trace, transpose, vandermonde, vecpotent, vectdim, vector, wronskian] > packages(); ⇒ [] > tpacmod(linalg, AVZ), tpacmod(linalg, det), tpacmod(linalg, diag); ⇒ false, true, true > tpacmod(SimpleStat, AGN), tpacmod(SimpleStat, Ds), tpacmod(SimpleStat, MCC); false, true, true > packages(); ⇒ [] > tpacmod(stats); [anova, describe, fit, importdata, random, statevalf, statplots, transform] > packages(); ⇒ [] |
Из примеров фрагмента следует, что вызовы процедуры tpacmod(М) как для получения списка экспортов пакетного модуля М, так и для тестирования имени быть экспортом пакетного модуля не загружают ни экспортов пакетного модуля в РОП, ни модуля в целом. Данное средство во многих случаях работы с пакетными модулями оказывается в значительной степени весьма полезным.
Рассмотрев основные вопросы ведения библиотек пользователя в среде Maple, довольно важным представляется и вопрос анализа библиотек на предмет их эффективности, ответ на который в значительной мере может прояснить статистический анализ динамики функционирования библиотек в процессе их реального использования.
Создав собственную Maple-библиотеку процедур с использованием вышеупомянутых подходов или каким-либо иным способом, естественно возникает задача ее оптимизации, в частности, с целью раскрытия частоты использования средств, содержащихся в ней, и основных ресурсов компьютера, используемых ими. В этом контексте, проблема оптимизации библиотек пользователя довольно актуальна. Для этих целей достаточно полезной представляется процедура StatLib(L) [41,103], обеспечивающая сбор основной статистики по заданной L библиотеке и возврату статистики для последующего анализа. Прежде всего, процедура StatLib предполагает, что анализируемая библиотека L находится в каталоге LIB с главной библиотекой Maple. В процессе своего выполнения процедура StatLib требует некоторых дополнительных ресурсов памяти и времени.
Процедура StatLib(L) в качестве первого обязательного аргумента L использует имя анализируемой Maple-библиотеки, расположенной в подкаталоге LIB главного каталога пакета, которая логически связана с главной Maple-библиотекой. Другие ее формальные аргументы (в количестве до 3) являются дополнительными и назначение кортежей их значений определяется следующим образом:
StatLib(L) – инициация сбора статистики по средствам библиотеки L в целом; StatLib(L, 0) – удаление всех файлов со статистической информацией по анали- зируемой библиотеке L;
StatLib(L, 1) – отмена сбора статистики по библиотеке L с сохранением получен- ных результатов;
StatLib(L, P) – инициация сбора статистики по процедуре P из библиотеки L; StatLib(L, T, 2) – возврат собранной статистики по библиотеке L либо по ее проце- дуре P в заданном разрезе T;
StatLib(L, T, 2, m) – возврат собранной статистики по библиотеке L либо по ее проце- дуре P в заданном T разрезе, характеризуемом числом m;
StatLib(L, T, N) – возврат собранной статистики по заданной процедуре N в требу- емом разрезе {calls, bytes, depth, maxdepth, time};
StatLib(L, abend) – завершение процедуры при возникновении критических ошибок.
Вызов процедуры StatLib(L) с одним фактическим аргументом L инициирует процесс сбора статистики по вызовам составляющих библиотеку L процедур. Данный процесс сбора может быть прекращен вызовом процедуры StatLib(L, 1), который обязателен при необходимости продолжения сбора статистики в последующих сеансах работы с пакетом, ибо он производит сохранение собранной статистики в пяти файлах, размещаемых в каталоге с библиотекой L. Имена этих файлов данных имеют одинаковый “$@_”префикс. Вызов процедуры с нулевым значением второго фактического аргумента возвращает NULL-значение с удалением файлов сбора статистики для данной библиотеки L. Данный вызов рекомендуется выполнять перед инициацией нового процесса профилирования процедур с целью сохранения его результатов в каталоге с библиотекой L. При этом, существующие статистические файлы данных с ранее собранной информацией могут быть предварительно сохранены в другом каталоге либо остаться в старом под иными именами.
Вызов процедуры StatLib(L, P) инициирует процесс сбора статистики по вызовам процедур, составляющих библиотеку L и определяемых их P-списком имен. При этом, запрашиваемые к профилированию процедуры не обязательно должны принадлежать библиотеке L – они могут находиться в любой библиотеке, логически связанной с главной библиотекой пакета, или быть активными в текущем Maple-сеансе. В противном случае инициируется ошибочная ситуация с возвратом соответствующей диагностики. Это позволяет производить анализ как всей библиотеки L в целом, так и в разрезе составляющих библиотекуе процедур (не совмещая оба эти процесса), а также любых активных либо доступных процедур текущего сеанса пакета.
Процедура обеспечивает возврат статистической информации в следующих пяти разрезах, определяемых ключевыми словами T = {calls, bytes, depth, maxdepth, time}, определяющими соответственно показатели: (1) количество вызовов, (2) объем используемой памяти, (3) глубина и (4) максимальная глубина вложенности, а также (5) использованное время в сек. Вызов процедуры StatLib(L, T, 2) возвращает массив числовых характеристик для всех профилируемых процедур библиотеки L {либо процедур, определенных P-аргументом при вызове StatLib(L, P)} на текущий момент в заданном T-разрезе (например, calls – количество вызовов процедуры), тогда как вызов процедуры StatLib(L, T, 2, m) возвращает массив для T-разреза тех профилируемых процедур, значения соответствующих T-разрезу характеристик которых не менее m-величины. При отсутствии таких строк у массива процедура возвращает lack-значение, информируя о том, что на данный момент ни одна из профилируемых процедур не обладает соответствующей T-разрезу характеристикой со значением, не меньшим, чем m. Данный массив построчно отсортирован в порядке убывания значений характеристик; при этом, для равных значений строки массива сортируются лексикографически.
Наконец, вызов StatLib(L, T, N) процедуры (если в качестве третьего аргумента N процедуры указано значение {symbol, string}-типа) возвращает значение характеристики процедуры с именем N (если таковая существует и ранее профилировалась) в заданном T-разрезе. Например, вызов StatLib(UserLib, calls, RmDir) возвращает количество вызовов процедуры RmDir библиотеки UserLib, если данная библиотека или процедура предварительно профилировались. На остальных кортежах значений фактических аргументов возвращается NULL-значение. Для обеспечения больших надежности и сохранности собираемой статистической информации рекомендуется периодически ее сохранять посредством вызовов StatLib(L, 1) с последующим возобновлением профилирования требуемых средств вызовом StatLib(L) процедуры.
Процедура допускает два режима мониторинга результатов профилирования процедур – динамический и разовый. Динамический режим обеспечивает довольно удобную возможность мониторинга посредством описанных выше вызовов процедуры в процессе профилирования, т.е. между двумя вызовами процедуры StatLib(L) и StatLib(L,1). При этом, не нарушается сам процесс профилирования. Тогда как разовый режим предоставляет возможность проводить выборочную проверку результатов предыдущего профилирования без возобновления самого процесса профилирования. Данный подход позволяет более гибко производить мониторинг процесса профилирования процедур как внутри него, так и вне.