Процедура email(F, H) базируется на предыдущей процедуре, наследуя два ее первых аргумента и расширяя действие первой на файлы данных типов {doc, rtf, htm}, и в более общем случае на файлы rlb-типа. Фрагмент ниже представляет текст процедуры.
email := proc(F::file, G::{string, symbol }) local h k t, , , ω ν, ; `if`( not type(eval(G), {'symbol', 'string'}), ERROR "<%1> is not a datafile path",( G), `if` type(( G, 'file'), assign(ω = G), [assign(ν = interface(warnlevel)), null interface(( warnlevel = 0)), assign(ω = MkDir(G, 1)), null(interface(warnlevel = ν))])), assign(' 'ν = cat(F, ".$$$")); assign(h = subs([seq(t = NULL, t = [k $ (k = 0 .. 31)])], readbytes( ,F ∞))), writebytes(ν, h), close(F, ν); try E_mail(ν ω, , 169), close(ν) catch "datafile <%1> does not contain email addresses": WARNING("email a\ ddresses have not been found, however they can be encoded in datafile <%\ 1>", F) end try end proc |
В целом ряде задач возникает необходимость извлечения из выражений корректных подвыражений, идентифицируемых их началом, задаваемым либо позицией, либо строкой. В этом отношении достаточно полезной может оказаться и процедура extexp, обеспечивающая вполне удовлетворительное решение данной задачи. Нижеприведенный фрагмент представляет исходный текст процедуры extexp и примеры ее применения.
extexp := proc(S::{string, symbol }, n::list({posint, string})) local a b c d k j p h t, , , , , , , , ; assign(a = "" || S, b = length(S), d = [ ], h = interface(warnlevel)), interface(warnlevel = 0); for j to nops(n) do if type(n[j], 'posint') then if n j[ ] ≤ b then assign(' 'c = a[n j[ ]], ' 't = n j[ ] + 1) else error "%-1 element of 2nd argument must be no more than %2 b\ ut has received %3", , ,j b n j[ ] end if else if not search( ,a n j[ ], ' 'p ) then error "%-1 element of 2nd argument not belong <%2>", ,j S else assign(' 't = p + length(n j[ ]), ' 'c = n j[ ]) end if end if; for k from t to b do c := cat(c, a k[ ]); try parse(c, 'statement') catch : next end try ; d := [op(d), c]; break end do end do; map(convert d, , whattype(S)), null interface(( warnlevel = h)) end proc > S:= `(a+b)/(c+d)+x*(x+y)/(a-b)`: extexp(S, [1, 12, "(x+y)", "(x"]); [(a+b), +x, (x+y)/(a-b), (x+y)] > P:= "proc () x:= proc () end proc end proc": extexp(P, ["proc ()", "x:= proc ("]); ["proc () x:= proc () end proc end", "x:= proc () end"] > A:=(x*cos(x)+y*sin(y))/(x^2+a*x+c): extexp(convert(A, 'string'), ["(x*cos(x)", "(x^2"]); ["(x*cos(x)+y*sin(y))", "(x^2+a*x+c)"] |
Вызов процедуры extexp(S, n) возвращает список подвыражений в строчном формате, которые были извлечены из строчного/символьного формата S исходного выражения на основе их начальных позиций, определяемых списком n. Список n содержит позиции начала подвыражений в S-строке и/или их префиксы в строчном формате. Тип возвращаемых элементов списка определяется типом первого фактического аргумента вызова процедуры. Процедура обрабатывает основные особые и ошибочные ситуации. Прием, используемый процедурой для извлечения корректных подвыражений, может быть достаточно полезным при программировании других приложений в среде Maple.
Задачи, имеющие дело с поиском минимума и/или максимума (минимакса) выражения имеют не только теоретическое значение для исследования качественных аспектов большого числа математических разделов, но и в большей степени в многочисленных приложениях анализа. Для решения задач данного вида пакет Maple имеет целый ряд инструментальных средств различного уровня. Здесь мы представим aAMV процедуру, до некоторой степени дополняющую стандартные инструментальные средства Maple для поиска минимакса алгебраических выражений, в качестве которых выступают элементы массивов различного типа.
aAMV := proc( A::{Array(numeric ), Vector(numeric ), Matrix(numeric ), array(numeric )}) local a b c d h p k x min max, , , , , , , , , ; global _Art_Kr_; assign(a = (x range:: → [seq(k, k = lhs( )x .. rhs( )x )]), '_Art_Kr_' = [ ]); assign(b = map(a, `if`(type(A, {Matrix, Vector}), [seq(1 .. ,k k = [op 1,( eval(A))])], [op 2,( eval(A))]))), assign(d = nops(b)), assign(c = [seq(cat(x p, ), p = 1 .. d)]); eval parse cat seq(( ( ( "seq(", p = 1 .. d), "assign('_Art_Kr_'=[op(_Art_Kr_),", convert(c, 'string'), "])" seq(, cat(",", convert(c[k], 'string'), "=", convert(b[k], 'string'), ")"), k = 1 .. d)))) ; assign(h = sort [( seq(A[op( )k ], k = _Art_Kr_)])), assign(min = [ [h 1]], max = [ [h -1]]); for k in _Art_Kr_ do if A[op(k)] = min[1] then min := [op(min), k] elif A[op( )k ] = max[1] then max := [op(max), k] end if end do; min max, , unassign '( _Art_Kr_') end proc > A := array(1..2,1..2,1..4,[]): A[1,1,1]:=68: A[2,1,1]:=65: A[1,2,1]:=42: A[2,2,1]:=42: A[1,1,2]:=65: A[2,1,2]:=42: A[1,2,2]:=350: A[2,2,2]:=350: A[1,1,3]:=144: A[2,1,3]:=67: A[1,2,3]:=85: A[2,2,3]:=350: A[1,1,4]:=88: A[2,1,4]:=78: A[1,2,4]:=89: A[2,2,4]:=56: A1:=LinearAlgebra[RandomMatrix](10, 18): > aAMV(A); ⇒ [42, [1, 2, 1], [2, 2, 1], [2, 1, 2]], [350, [1, 2, 2], [2, 2, 2], [2, 2, 3]] > aAMV(A1); ⇒ [-99, [10, 10], [8, 14]], [98, [3, 13]] |
Вызов процедуры aAMV(A) возвращает двухэлементную последовательность вложенных списков. Первый элемент первого списка определяет значение минимального элемента массива А типов {array, Array, Matrix, Vector}, чьи элементы имеют numeric-тип, тогда как остальные его элементы определяют списки координат таких минимальных элементов. Тогда как первый элемент второго списка определяет значение максимального элемента массива A, в то время как остальные его элементы определяют списки координат таких максимальных элементов. Процедура aAMV применима к массивам указанного типа и любой размерности. Данная процедура весьма полезна во многих приложениях.
Представленные в данном разделе средства вполне обозримы и достаточно прозрачны, составляя небольшую часть нашей Библиотеки. Они предназначены для иллюстрации как организации процедур в среде Maple, так и для используемых ими ряда полезных приемов программирования. В заключение настоящей главы вкратце остановимся на вопросах отладки Maple-процедур.
Проблема отладки может возникать или при появлении рассмотренных выше, или других особых и аварийных ситуаций, либо при получении некорректных с точки зрения решаемой задачи результатов. В настоящее время проблема отладки ПС достаточно хорошо разработана и на данном вопросе нет особого смысла останавливаться. Ибо имеющий определенный компьютерный навык пользователь вполне знаком с данным вопросом. Из простых средств отладки можно отметить методы контрольных точек, трассировки (прокрутки) и др. Maple-язык в качестве такого средства предлагает метод трассировки вычислений, поддерживаемый процедурами {trace, debug}, представляющими на самом деле одну и ту же процедуру, но с альтернативными идентификаторами. Поэтому, говоря о trace-процедуре, будем иметь в виду и альтернативную ей debug-процедуру, и наоборот.
В тестирующем режиме, определенном процедурой {trace|debug}(P1, P2,...,Pn), производится трассировка каждого вызова Рк-процедур/функций, указанных в списке фактических аргументов функции до тех пор, пока не будет {untrace|undebug}(P1, P2, ..., Pn)вызова процедуры соответственно, отменяющего режим тестирования всех либо части тестируемых Pk-процедур/функций. Для трассируемой процедуры/функции на печать выводятся точки их вызова, результаты всех выполняемых промежуточных вычислений и предложений, а также точки выхода. В точках входа указываются фактические значения аргументов, а в выходных – возвращаемые ими результаты. Детально вопросы использования данных средств для отладки процедур рассмотрены в [12], исходную версию книги можно бесплатно получить по адресу [91].
Для отладки механизма вызовов процедур из других процедур весьма полезным средством может оказаться и процедура where(|<Число>), по которой выводится содержимое стэка вызовов процедур на глубину, определяемую значением (целого числа) фактического аргумента функции. Вызов процедуры where() определяет трассировку вызовов процедур, начиная с верхнего уровня; выводятся выполняемые предложения процедур и значения передаваемых процедурам фактических аргументов. При определении глубины стэка выводятся только элементы заданного числа его нижних уровней. С учетом сказанного, вызов where-процедуры должен указываться внутри процедуры, трассировка вызовов которой должна отслеживаться, как это иллюстрирует простой фрагмент трассировки вызовов Kr-процедуры на глубину 5 стэка вызовов процедуры: