savem1(F, M) и readm1(R)
соответственно, где F – имя или полный путь к файлу внутреннего Maple-формата (mфайлу) и М – программный модуль первого типа или их последовательность. При этом, модули не должны иметь protected-атрибута. Процедура savem1 предназначена для сохранения программных модулей первого типа в файлах внутреннего Maple-формата (mфайлах); если в качестве F-аргумента указан не m-файл, то к его имени добавляется расширение “.m”. Успешный вызов процедуры возвращает путь к созданному m-файлу с сохраненными в нем модулями M. Тогда как процедура readm1(R) читает в текущий сеанс файл R с корректной активацией сохраненных ранее в нем по savem1-процедуре программных модулей. Успешный вызов процедуры возвращает NULL-значение, т.е. ничего. Ниже представлен фрагмент с исходными текстами обеих процедур и примерами их применения для сохранения/чтения программных модулей первого типа.
savem1 := proc(F::{string, symbol }, M::mod1) local a; if not (map(type, {args 2 .. -1[ ]}, 'mod1') = {true}) then error " modules should be of the first type" end if; if "" || F[-2 .. -1] ≠ ".m" then a := F || ".m" else a := F end if; seq(assign(args[ ]k = convert(eval args[ ]( k ), 'string')), k = 2 .. nargs ;) (proc() save args, a end proc )(args 2 .. -1[ ]), a end proc > M:= module () export x; x:= () -> `*`(args)/nargs end module: M1:= module () export y; y:= () -> `+`(args)/nargs end module: M2:= module () export z; z:= () -> `+`(args) end module: M3:= module () export h; h:= () -> evalf(sqrt(`+`(args)), 5) end module: > savem1("C:\temp\Academy", M, M1, M2, M3); "C:/temp/Academy.m" |
readm1 := proc(F::file) local b c k, , ; assign(b = { }, c = 10 17/ ); if "" || F[-2 .. -1] ≠ ".m" then error "file should has internal Maple format, but had received `%1`-type"Ftype(, F) end if; do if c ≠ 0 then c := readline(F); if c[1] = "I" then b := {op(b), Iddn1( )c } end if else break end if end do; close(F), assign(' 'b = map(convert b, , 'string')); read F; for k in b do try parse(cat(k, ":=", eval(`` || k), ":"), 'statement'); NULL catch : error "file <%1> should be saved by procedure `savem1`", F end try end do end proc > restart; readm1("C:/temp/pdf.htm"); Error, (in readm1) file should has internal Maple format, but had received `.htm`-type > readm1("C:/temp/grsu.m"); Error, (in readm1) file <C:/temp/grsu.m> should be saved by procedure `savem1` > restart; readm1("C:\temp\Academy.m"); > map(type, [M, M1, M2, M3], `module`), with(M), with(M1), with(M2), with(M3); [true, true, true, true], [x], [y], [z], [h] > M:- x(64, 59, 39, 17, 10, 44), x(64, 59, 39, 17, 10, 44); 183589120, 183589120 > 6*M1:- y(64, 59, 39, 17, 10, 44), 6*y(64, 59, 39, 17, 10, 44); ⇒ 233, 233 > M2:- z(64, 59, 39, 17, 10, 44), z(64, 59, 39, 17, 10, 44); ⇒ 233, 233 > M3:- h(64, 59, 39, 17, 10, 44), h(64, 59, 39, 17, 10, 44); ⇒ 15.264, 15.264 |
Обе процедуры обрабатывают основные особые и ошибочные ситуации. Алгоритм первой процедуры базируется на строчном представлении определения программного модуля, сохраняемого в специальном формате в файле внутреннего формата. Тогда как вторая процедура использует представление сохраненного в m-файле модуля, используя структуру файлов такого типа и специальную процедуру Iddn1, обеспечивающую возврат имен Maple-объектов, сохраненных в файлах внутреннего Maple-формата. В качестве весьма полезного упражнения читателю рекомендуется рассмотреть организацию обоих процедур.
В ряде случаев возникает необходимость анализировать m-файл внутреннего формата Maple на предмет находящихся в нем объектов. Данную задачу решает mnames-процедура, исходный текст и примеры применения которой приведены ниже. Вызов процедуры mnames(F) для случая анализа в среде Maple 6 файла F, подготовленного в среде Maple 7 - 10, возвращает только множество имен объектов с выводом сообщения.
mnames := proc(F::file) local a b c h t tab, , , , , ; if Ftype(F) ≠ ".m" then error "datafile <%1> has a type different from m-type", F else close(F), assign(a = { }, b = Release( ), c = parse(readline(F)[2])); do h := readline(F); if h = 0 then close(F); break else if h[1] = "I" then a := {op(a), Iddn1(h)} minus {false} end if end if end do; if b = 6 and 7 ≤ c then a, WARNING("procedure return presents the nam\ es of Maple objects only, because m-file had been created in release >\ =7 whereas the current release is 6", b) else read F; for h in a do t := whattype eval(( h)); if type(tab t[ ], 'assignable') then tab t[ ] := { }; tab t[ ] := {h, op(tab t[ ])} else tab[t] := {h, op(tab[t])} end if end do; `if`(nargs = 1, NULL, Unassign op(( a))), eval(tab) end if end if end proc > mnames("C:/Temp/Test8.m", 10); AGN, L1, S, Akr, Grod, AVZ, eval(m); table([float = {AGN}, integer = {AVZ}, list = {L1, L}, fraction = {Akr}, set = {S, S1}, module = {M, M1}, array = {a, v, m, v1, m1, a1}, table = {T1, T}, complex = {Grod}, procedure = {P}]) AGN, L1, S, Akr, Grod, AVZ, m |
Тогда как аналогичный вызов mnames(F) для случая анализа в среде Maple 7 - 10, файла F, подготовленного в среде Maple 6 - 10, не только возвращает таблицу, чьими входами являются типы объектов файла, а выходами множества соответствующих им имен, но и делает эти объекты активными в текущем сеансе. Тогда как вызов mnames(F, P) при тех же предположениях, где P – произвольное Maple-выражение, оставляет имена объектов файла F неопределенными, возвращая при этом вышеуказанную таблицу. Процедура неоднократно успешно использовалась для анализа незнакомых файлов внутреннего Maple-формата. Целый ряд других полезных средств для сохранения программных модулей в файлах внутреннего Maple-формата, а также для работы с файлами указанного формата представлен в наших книгах [41,42,103] и в прилагаемой к ним Библиотеке для пакета Maple релизов 6 – 10. Наряду с практическим интересом данные средства представляют определенный интерес и для практического программирования в Maple, предлагая целый ряд полезных и эффективных приемов программирования.
В предыдущей главе был представлен ряд базовых функциональных средств Maple-языка по обеспечению работы с основными типами данных и структур данных. Здесь мы дадим более полное, хотя и не исчерпывающее представление данных средств, которые наиболее часто используемы в программировании различных Maple-приложений.
В настоящей главе рассмотрим базовые средства работы в среде Maple-языка с данными строчного (string) и символьного (symbol) типов более детально. Для тестирования выражений типа string используется уже упоминаемая whattype(S)-процедура, возвращающая string-значение, если результат вычисления S-выражения имеет string-тип. Тестирование можно осуществлять и по type(S, 'string')-функции, возвращающей true-значение в случае S-строки и false в противном случае. Для тестирования выражений типа symbol используется уже упоминаемая whattype(S)-процедура, возвращающая symbolзначение, если результат вычисления S-выражения имеет symbol-тип. Тестирование можно производить и по type(S, 'symbol')-функции, возвращающей true-значение в случае S-символа и false в противном случае. Данные строчного и символьного типов играют весьма важную роль при операциях ввода/вывода, работе с текстовой информацией, символьных вычислениях и преобразованиях и др. При этом, данные этих типов наиболее широко используются, в первую очередь, в задачах символьных обработки и вычислений [8-14,41,78-90,55,58-62,103,108,109].
Символьные значения представляются как простыми идентификаторами, так и составными, ограниченными верхники кавычками (`); при этом, любая цепочка символов, ограниченная кавычками, рассматривается в качестве символьного значения. Тестирующими средствами Maple-языка символьные выражения распознаются как значения типа {symbol, name}, как это иллюстрирует следующий весьма простой пример: > whattype(AV), whattype(`A V Z`), whattype(Academy_Noosphere); symbol, symbol, symbol
> type(AV, 'symbol'), type(`A V`, 'symbol'), type(Academy_Noosphere, 'name'); true, true, true
Строчные выражения представляются значениями, ограниченными двойными кавычками ("); при этом, любая цепочка символов, ограниченная такими кавычками, рассматривается в качестве строчного значения. Тестирующими средствами Maple-языка строчные значения распознаются как значения string-типа, как это иллюстрирует следующий простой пример:
> whattype("AV"), whattype("A V Z"), whattype("Academy"); ⇒ string, string, stringl
> type("AV",'string'), type("A V",'string'), type("Academy_2006", 'string'); ⇒ true, true, true
При этом, со строчной информацией на уровне отдельного символа Maple-язык работает как со строками длины 1, например length("A")=1, что не требует специального определения типа для отдельных символов. В дальнейшем для строчных и символьных выражений будем использовать групповое имя «символьные» выражения. Для конвертации строчных выражений в символьные и наоборот служит convert-функция, как это иллюстрирует следующий простой фрагмент:
> convert("AVZ", 'symbol'), convert(AVZ, 'string'); ⇒ AVZ, "AVZ"
> ``||"AVZ", ""||AVZ, cat(``, "AVZ"), cat("", AVZ); ⇒ AVZ, "AVZ", AVZ, "AVZ"
> cat(a + b, 'string'), ""||(a + b); ⇒ || (a + b) || string, "" || (a + b)
Конвертацию можно проводить и посредством cat-функции и ||-оператора конкатенации, как иллюстрирует второй пример фрагмента. Тогда как последний пример подтверждает, что именно convert-функция является наиболее общим средством подобной конвертации символьно/строчных выражений.
Для обеспечения работы со строчными выражениями Maple-язык располагает рядом базовых средств манипулирования со строками, пригодными, в свою очередь, и для обработки символьных значений. Немногочисленные средства собственно Maple-языка по обеспечению работы с данными указанных двух типов достаточно прозрачны и в том или ином виде имеются во всех современных системах программирования, поэтому особых пояснений не требуют. Отметим лишь средства, наиболее часто используемые в практическом программировании в среде Maple. Их специфические свойства и особенности достаточно детально рассмотрены в [8-14,29,30,41,103,108].