Смекни!
smekni.com

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

Правила подстановок Е задаются списком уравнений вида [Y1 = X1, Y2 = X2, …, Yn = Xn]; где для обеих частей уравнений предполагаются выражения типов {string, symbol}. При этом, алгоритм применения системы подстановок Е состоит в следующем: первая подстановка Е применяется к S до ее полного исчерпания в S, затем аналогичная операция проделывается со второй подстановкой из Е, и так далее до полного исчерпания всех подстановок из Е.

При кодировании четвертого дополнительного аргумента insensitive процедура Sub_st поддерживает регистро-независимый, в противном случае выполняется регистро-зависимый поиск вхождений левых частей подстановок. Наконец, через третий фактический аргумент R возвращается следующее значение: (1) true, если обработка S была завершена успешно, (2) результат обработки S до ситуации обнаружения подстановки, ведущей к бесконечному процессу (циклическая работа). Выше представлен фрагмент с исходным текстом процедуры Sub_st и результатами ее применения.

Наряду с целым рядом средств, обеспечивающих разнообразную обработку символьных и строчных выражений, наша библиотека [41,103] содержит и средства поддержки ряда полезных в практическом отношении подстановок. Читатель и сам может запрограммировать требуемые для своих конкретных приложений интересные средства, используемые многократно.

В определенной мере к средствам, обеспечивающим подстановки в выражения, примыкает и специальное use-предложение языка, имеющее формат кодирования: use <ПВ> in <ПП> end use

где ПВ – последовательность выражений типа {`=`, equation} и ПП – последовательность предложений Maple (тело use-предложения). ПВ определяет последовательность связывающих форм. В простейшем виде связывающая форма представляет собой уравнение (точнее, правило подстановки), чья левая сторона представляет имя, тогда как правой стороной уравнения может быть любое выражение языка, но не их последовательность. Другие виды связывающих форм определяются в терминах эквациональных связывающих форм. В качестве связывающих форм могут выступать выражения выбора члена модуля; связывающая форма вида М:- e эквивалентна эквациональной связывающей форме e = М:- e. Наконец, в качестве связывающей формы может выступать модульное выражение либо его имя. Использование модуля М в качестве связывающей формы эквивалентно определению уравнения e = М:- e для всех экспортов e модуля М. Предложение use отличается от всех других предложений Maple-языка тем, что оно разрешается в течение автоматического упрощения, а не в процессе вычислений. Предложение use не может быть вычислено.

Предложение use вызывает синтаксическое преобразование его тела согласно подстановкам, указанным в последовательности связывающих форм. Однако, оно в отличие от простых подстановок производит их в соответствии со статическими правилами просмотра Maple-языка. Каждое use-предложение вводит новый контур связывания, в пределах которого в течение упрощения имена левых частей каждого из уравнений связывания заменяются соответствую-ими выражениями правых частей уравнений. Тело useпредложения "перезаписывается", выполняя указанные замены.

Каждое вхождение связующего имени (левая часть) заменяется соответствующим ему выражением (правая часть) всюду по телу use-предложения. Когда тело use-предложения вычисляется, значение связующего имени вычисляется один раз для каждого его вхождения. Это означает, что в то время как само use-предложение не налагает никаких ограничений в процессе вычисления, следует проявлять внимательность в случае, когда правые части уравнений связывания могут выполнять важные вычисления. Правые части связывающих форм не вычисляются при обработке use-предложения. Детальнее с useпредложением можно ознакомиться по конструкции ?use, здесь же мы представим примеры, иллюстрирующие применение use-предложения в различных ситуациях:

> use a = 64, b = 59, c = 39, d = 17 in (a + b)/(c+d) end use; ⇒ 123/56

> P:= proc(n::posint) add(a+k, k=1..n) end proc: P(17); ⇒ 153 + 17 a > use a = 64 in proc(n::posint) add(a + k, k=1..n) end proc end use; proc(n::posint) add(64 + k, k = 1 .. n) end proc

> %(17); ⇒ 1241

> use b = 64 in proc(n::posint) local b; add(b+k, k=1..n) end proc end use; proc(n::posint) local b; add(b + k, k = 1 .. n) end proc

> use add = seq in proc(n::posint) local b; add(b+k, k=1..n) end proc end use; proc(n::posint) local b; :-seq(b + k, k = 1 .. n) end proc > %(10); ⇒ b + 1, b + 2, b + 3, b + 4, b + 5, b + 6, b + 7, b + 8, b + 9, b + 10

> use `+` = `*` in proc(n::posint) local b; add(k, k=1..n); b:=proc() global c; c*`+`(args) end proc end proc end use;

proc (n::posint) local b; add(k,k = 1 .. n); b := proc () global c; c*`+`(args) end proc end proc

> use `+` = ((a, b) -> a * b) in 64 + 56 end use; ⇒ 3584

> use a = b in module() export a; a:=() -> add(args[k], k=1..nargs) end module end use; module() export a; end module

> %:- a(64, 59, 39, 10, 17); ⇒ 189 > use `and` = `or` in proc() if nargs > 6 and args[1] = 64 then 2006 end if end proc end use; proc() if :-`or`(6 < nargs, args[1] = 64) then 2006 end if end proc > %(64); ⇒ 2006

Из примеров фрагмента следует, что use-предложение в процедурах и модулях игнорирует замены локальных, глобальных и экспортируемых переменных, возвращая свое тело лишь упрощенным без выполнения тех замен, левые части которых определяют имена указанного типа переменных. Более того, use-предложение не производит прямых замен, в частности, бинарных инфиксных операторов (например, `+` и `*`) или унарных префиксных или постфиксных операторов, как это иллюстрирует 8-й пример фрагмента. Тогда как такие операторы можно заменять, если правые части связывающей формы определяют процедуры или модули, как это иллюстрирует 9-й пример фрагмента. По use-предложению можно заменять такие операторы как: `+`, `*`, `-`, `/`, `^`, `!`, `and`, `or`, `not`, `=`, `<>`, `<`, `<=`.

Use := proc(P::anything) if nargs = 1 then P

elif type(P `module`, ) then

WARNING("1st

argument is a module; apply the `use`-clause");

return P else try eval parse SUB_S( ( ([seq(`if`( type(args[ ]k , 'equation') and type(lhs args[ ]( k ), 'symbol'), lhs args[ ]( k ) = convert(rhs args[ ]( k ), 'string'), NULL), k = 2 .. nargs)], convert(eval(P), 'string')))) catch : P end try

end if

end proc

> Use(proc(n::posint) local b; add(k, k=1..n); b:= proc() global c; c*`+`(args) end proc end proc, `+` = `*`);

proc(n::posint) local b; add(k, k = 1 .. n); b := proc() global c; c*`*`(args) end proc end proc > Use(proc(n::posint) local b; add(k, k=1..n); b:=proc() global c; c*`+`(args) end proc end proc, c = d); proc(n::posint) local b; add(k, k = 1 .. n); b := proc() global c; c*`+`(args) end proc end proc > Use(proc(n::posint) local b; add(k, k=1..n); b:=proc() global c; c*`+`(args) end proc end proc, a = c); proc(n::posint) local b; add(k, k = 1 .. n); b := proc() global c; c*`+`(args) end proc end proc > Use(proc(n::posint) local b; add(k, k=1..n); b:=proc() global c; c*`+`(args) end proc end proc, k = j); proc(n::posint) local b; add(j, j = 1 .. n); b := proc() global c; c*`+`(args) end proc end proc > Use((a+b)/d, d = 0);

a + b

d

> use d = 0 in (a+b)/d end use;

Error, numeric exception: division by zero

> Use(proc(n::posint) local b; add(b+k, k=1..n) end proc, b = 64);

proc(n::posint) local b; add(b + k, k = 1 .. n) end proc

> Use(module() export a; a:=() -> add(args[k], k=1..nargs) end module, a=b); Warning, 1st argument is a module; apply the `use`-clause

module() export a; end module

> %:- a(64, 59, 39, 10, 17); ⇒ 189

> Use(proc() if nargs > 6 and args[1] = 64 then 2006 end if end proc, `and` = `or`); proc() if 6 < nargs or args[1] = 64 then 2006 end if end proc

> Use(proc() Digits:= 40; a*1/100000000000000000000001.0, (64 + Digits^a) end proc, a = 2); proc () Digits := 40; 0.2000000000*10^(-22), 64 + Digits^2 end proc

> %(); ⇒ 0.2000000000 10 -22, 1664

Представленная выше процедура Use(P, x=x1, y=y1, …) в ряде случаев оказывается неплохим дополнением use-предложению, обеспечивая подстановки правых частей уравнений, определяемых фактическими аргументами, начиная со второго, вместо вхождений в выражение Р соответствующих им левых частей. При этом, в качестве первого аргумента Р может выступать любое выражение, кроме модулей; в противном случае вызов процедуры возвращает исходное выражение с выводом соответствующего предупреждения. На остальных выражениях Р вызов процедуры Use(P, x = x1, y = y1,…) во многом подобен результатам применения use-предложения, тогда как имеется и целый ряд особенностей. Например, Use-процедура позволяет делать прямые замены вышеуказанных операторов, обрабатывает особые и ошибочные ситуации и др. Предыдущий фрагмент представляет исходный текст процедуры Use и примеры ее применения. При этом, если необходимо произвести обработку Use-процедурой последовательности выражений или предложений, то их можно обрамлять процедурой, как иллюстрирует последний пример фрагмента. В ряде приложений Use-процедура предпочтительнее use-предложения. Наша Библиотека [41,103,109] представляет целый ряд достаточно полезных средств для обеспечения различного рода как символьных, так и алгебраических подстановок, ряд из которых довольно неплохо дополняют стандартные средства подобного типа. Многие из них используются и другими средствами Библиотеки, в ряде случаев существенно упрощая программирование и делая реализуемые ими алгоритмы более програчными.