Смекни!
smekni.com

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

Процедурный формат оператора:

> &ma(h(x), g(y), v(z), r(g), w(h), (a + b)/(c - d)); h(x), g(y), v(z), r(g), w(h);

a + b a + b a + b a + b a + b c − d, c − d, c − d, c − d, c − d

> &ma('x', 'y', 'z', 'g', 'h', "(a + b)/(c - d)"); x, y, z, g, h;

"(a+b)/(c-d)", "(a+b)/(c-d)", "(a+b)/(c-d)", "(a+b)/(c-d)", "(a+b)/(c-d)"

> &ma('x', 'y', 'z', 'g', 'h', _NULL); x, y, z, g, h;

> &ma'x', 'y', 'z', 'g', 'h', 2006); x, y, z, g, h; ⇒ 2006, 2006, 2006, 2006, 2006 > &ma('x', 'y', 'z', 'g', 'h', sin(a)*cos(b)); x, y, z, g, h; sin(a) cos(b), sin(a) cos(b), sin(a) cos(b), sin(a) cos(b), sin(a) cos(b)

Операторный формат:

> ('x', 'y', 'z', 'g', 'h') &ma _NULL; x, y, z, g, h;

> ('x', 'y', 'z', 'g', 'h') &ma 2006; x, y, z, g, h; ⇒ 2006, 2006, 2006, 2006, 2006

> ('x', 'y', 'z', 'g', 'h') &ma (sin(a)*cos(b)); x, y, z, g, h; sin(a) cos(b), sin(a) cos(b), sin(a) cos(b), sin(a) cos(b), sin(a) cos(b) > ('x', 'y', 'z', 'g', 'h') &ma ((a + b)/(c - d)); x, y, z, g, h;

a + b a + b a + b a + b a + b

, , , ,

c − d c − d c − d c − d c − d

Для проверки идентификатора на предмет его определенности используется встроенная функция assigned языка, кодируемая в виде assigned(Идентификатор) и возвращающая значение true в случае определенности идентификатора (простого, индексированного или вызова функции/процедуры), и false-значение в противном случае. При этом, следует иметь в виду, что определенным идентификатор полагается тогда, когда он был использован в качестве левой части (:=)-оператора присвоения, даже если его правая часть являлась неопределенной. Или он получил присвоение по аssign-процедуре. Следующий простой фрагмент иллюстрирует вышесказанное:

> agn:=1947: avz:=grodno: assign(vsv=1967, art=kr): seq(assigned(k), k=[agn, avz, vsv, art]); true, true, true, true

> map(type,[agn, avz, vsv, art],'assignable'); ⇒ [false, true, false, true]

> map(assigned, [agn, avz, vsv, art]);

Error, illegal use of an object as a name

С другой стороны, по конструкции type(Id, 'assignable') мы можем тестировать допустимость присвоения Id–переменной (простой, индексированной или вызова функции/процедуры) выражения: возврат true-значения говорит о такой возможности, false – нет. Следует обратить внимание на последний пример фрагмента, иллюстрирующий некорректность использования встроенной функции map при попытке организации простого цикла.

Вызов функции indets(W {, <Тип>}) возвращает множество всех идентификаторов заданного его первым фактическим W-аргументом Maple-выражения. При этом, W-выражение рассматривается функцией рациональным, т.е. образованным посредством {+, -, *, /}-операций. Поэтому в качестве результата могут возвращаться не только простые идентификаторы W-выражения, но и неопределенные его подвыражения. В случае кодирования второго необязательного аргумента, он определяет тип возвращаемых идентификаторов, являясь своего рода фильтром. В качестве второго фактического аргумента могут выступать как отдельный тип, так и их множество в соответствии с типами, распознаваемыми тестирующей type-функцией языка, рассматриваемой детально ниже. Следующий фрагмент иллюстрирует применение indets-функции для выделения идентификаторов переменных:

> indets(x^3 + 57*y - 99*x*y + (z + sin(t))/(a + b + c) = G);

{sin(t), x, y, z, t, a, b, c, G}

> indets(x^3 + 57*y - 99*x*y + (z + sin(t))/(a + b + c) = G, function); ⇒ {sin(t)} > indets(x^3 + z/y - 99*x*y + sin(t), {integer, name});

{-99, -1, 3, x, y, z, t}

> indets(x^3 + z/y - 99*x*y + sin(t), {integer, name, `*`, `+`});

{-99 -1 3, , , , , , ,x z y t

, x3 + − z 99 x y + sin( )t , −99 x y} z

y y

> indets(x^3 + z/y - 99*x*y + sin(t), {algnum, trig});

{-99, -1, 3, sin(t)}

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

Для возможности использования произвольного А-выражения в качестве объекта, которому могут присваиваться значения, Maple-язык располагает evaln-функцией, кодируемой в виде evaln(A) и возвращающей имя выражения. В качестве А-выражения допускаются: простой идентификатор, индексированный идентификатор, вызов функции/ процедуры или конкатенация символов. В результате применения к А-выражению функции evaln оно становится доступным для присвоения ему значений, однако если ему не было сделано реального присвоения, то применение к нему assigned-функции возвращает значение false, т.е. А-выражение остается неопределенным. Таким образом, по конструкции Id:= evaln(Id) производится отмена присвоенного Id-идентификатору значения, делая его неопределенным, как это иллюстрирует следующий простой фрагмент:

> Asv:= 32: assigned(Asv); Asv:= evaln(Asv): Asv, assigned(Asv); true

Asv, false

> Asv:= 67: assigned(Asv); Asv:= 'Asv': Asv, assigned(Asv); true

Asv, false

Из приведенного фрагмента непосредственно следует, что первоначальное присвоение Asv-идентификатору значения делает его определенным, на что указывает и результат вызова assigned-функции. Тогда как последующее выполнение Asv:=evaln(Asv) предложения делает Asv-идентификатор вновь неопределенным. Вторым способом приведения идентификатора к неопределенному состоянию является использование конструкции вида Id:= 'Id', как это иллюстрирует второй пример предыдущего фрагмента.

Для выполнения присвоений можно воспользоваться и assign-процедурой, допускающей в общем случае три формата кодирования, а именно: assign({A, B|A = B|C}), где А – некоторый идентификатор, В - любое допустимое выражение и С - список, множество либо последовательность уравнений. В первых двух случаях применение assign-процедуры эквивалентно применению (:=)-оператора присвоения, тогда как третий случай применяется для обеспечения присвоения левой части каждого элемента списка, множества или последовательности уравнений. Простой фрагмент иллюстрирует вышесказанное:

> assign(AGn, 59); assign(AVz=64); assign([xx=1, yy=2, zz=3, h=cos(y)*tan(z)]);

> assign({xx1=4, yy1=5, zz1=6, y=x*sin(x)}); [AGn, AVz, xx, yy, zz, xx1, yy1, zz1, y, h];

[59, 64, 1, 2, 3, 4, 5, 6, x sin(x), cos(x sin(x)) tan(z)]

> assign('x', assign('y', assign('z', 64))); [x, y, z]; ⇒ [64] # Maple 7 и выше

> assign('x', assign('y', assign('z', 64))); [x, y, z]; # Maple 6 и ниже Error, (in assign) invalid arguments

> `if`(type(AV, 'symbol') = true, assign(AV, 64), false); AV; ⇒ 64

> GS:= op([57*sin(19.95), assign('VG', 52)]) + VG*cos(19.99); ⇒ GS := 72.50422598

Успешное выполнение assign-процедуры производит указанные присвоения и возвращает NULL-значение, в противном случае инициируется соответствующая ошибочная ситуация. Данная ситуация, в частности, возникает при попытке рекурсивного вызова assign-процедуры для релизов 6 и ниже, тогда как в более старших релизах подобного ограничения нет. По отношению к процедуре assign релизы пакета характеризуются весьма существенной несовместимостью, что стимулировало нас к созданию аналога стандартной процедуры, который не только устраняет указанную несовместимость, но и расширяет функциональные возможности [31,39,41-43,45,46,103]. Это и другие наши средства рассмотрены детально в книге [103] и представлены в прилагаемой к ней Библиотеке программных средств.

При этом, следует отметить, что в целом ряде случаев assign-процедура является единственно возможным способом присвоения значений, например, внутри выражений, как это иллюстрирует последний пример фрагмента, который содержит структуры и функции, рассматриваемые ниже. Механизм assign-процедуры достаточно эффективен в различных вычислительных конструкциях, многочисленные примеры применения которого приводятся ниже при рассмотрении различных аспектов Maple-языка, а также в нашей Библиотеке [103].

Обратной к assign-процедуре является unassign-процедура с форматом кодирования: unassign(<Идентификатор_1>, <Идентификатор_2>, ...)

отменяющая определения для указанных последовательностью ее фактических аргументов идентификаторов. Успешный вызов процедуры unassign выполняет отмену назначений, возвращая NULL-значение. Однако, процедура не действует на идентификаторы с protected-атрибутом, инициируя ошибочную ситуацию с выводом соответствующей диагностики. Приведем простые примеры на использование unassign-процедуры.

> AS:= 39: AV:= 64: AG:= 59: Kr:= 10: Art:= 17: AS, AV, AG, Kr, Art;

39, 64, 59, 10, 17

> unassign(AS, AV, AG, Kr, Art); Error, (in unassign) cannot unassign '39' (argument must be assignable) > unassign('AS', 'AV', 'AG', 'Kr', 'Art'); AS, AV, AG, Kr, Art;

AS, AV, AG, Kr, Art

> `if`(type(AV, 'symbol') = true, assign(AV, 64), unassign('AV')); AV; ⇒ 64

В приведенном фрагменте пяти переменным присваиваются целочисленные значения, а затем по unassign-процедуре делается попытка отменить сделанные назначения. Попытка вызывает ошибочную ситуацию, обусловленную тем, что в точке вызова процедуре unassign передаются не сами идентификаторы, а их значения (кстати, именно данная ситуация одна из наиболее типичных при ошибочных вызовах assign-процедуры). Для устранения ее идентификаторы следует кодировать в невычисленном формате (кодируя в апострофах), что иллюстрирует повторный вызов unassign-процедуры. Последний пример иллюстрирует применение процедур assign и unassign в условном if-предложении языка, по которому AV-переменной присваивается целочисленное значение, если она была неопределенной, и отменяется ее определение в противном случае.