Смекни!
smekni.com

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

Идентификатор[Последовательность индексов] {;|:}

возвращающее элемент структуры с указанным идентификатором и заданными значениями индексов. Данное предложение имеет смысл только для структур, в которых можно выделить составляющие их элементы (списки, множества, массивы, матрицы и др.). Следующий простой пример иллюстрирует применение предложения выделения:

> L:= [59, 64, 39, 10, 17]: S:={V, G, Sv, Art, Kr}: L[3], S[5], S[3], L[4];

39, Sv, Art, 10

Наконец, идентификатор функции/процедуры кодируется в следующем формате: Идентификатор(Последовательность фактических аргументов)

определяя вызов функции с заданным именем с передачей ей заданных фактических аргументов, например: sin(20.06); ⇒ 0.9357726776.

Для идентификаторов любых конструкций Maple-языка допускается использование алиасов (дополнительных имен), позволяющих обращаться к конструкциям как по их основным именам, так и по дополнительным. Данный механизм языка обеспечивается встроенной alias-функцией, кодируемой в следующем формате: alias(alias_1=Id, alias_2=Id, ... , alias_n=Id)

где Id - основное имя, а alias_j - присваиваемые ему алиасы (j=1..n), например:

> G:= `AVZ`: alias(year = 'G', Grodno = 'G', `ГрГУ` = 'G'); ⇒ year, Grodno, ГрГУ

> [G, year, Grodno, `ГрГУ`]; ⇒ [AVZ, AVZ, AVZ, AVZ]

> alias(e = exp(1)); ⇒ year, Grodno, ГрГУ, e

> evalf(e); ⇒ 2.718281828

В приведенном фрагменте проиллюстрировано, в частности, определение более привычного e-алиаса для основания натурального логарифма, вместо принятого (на наш взгляд не совсем удачного) в пакете exp(1)-обозначения. Алиасы не допускаются только для числовых констант; при этом, в качестве Id-параметров alias-функции должен использоваться невычисленный идентификатор (т.е. кодируемый в апострофах), а не его значение. Если вызов alias-функции завершается (;)-разделителем, то возвращается последовательность всех на текущий момент присвоенных алиасов сеанса работы с ядром пакета. Механизм алиасов имеет немало интересных приложений, детальнее рассматриваемых в наших книгах [10-12,91].

Близкой по назначению к alias-функции является и функция macro формата: macro(X1 = Y1, ...., Xn = Yn)

возвращающая NULL-значение, т.е. ничего, и устанавливающая на период сеанса работы с ядром пакета односторонние соотношения X1 ⇒ Y1, ..., Xn ⇒ Yn. Точнее, любое вхождение Xj-конструкции в Input-параграфе либо при чтении ее из файла замещается на приписанную ей по macro-функции Yj-конструкцию. Исключением является вхождение Xj-конструкций в качестве формальных аргументов и локальных переменных процедур. В данном отношении macro-функция отличается от традиционного понятия макроса и более соответствует однонаправленному алиасу. Функция macro может быть определена для любой Maple-конструкции, исключая числовые константы. Более того, фактические аргументы macro-функции не вычисляются и не обрабатываются другими macro-функциями, не допуская рекурсивных macro-определений. Для изменения определения macro вполне достаточно выполнить новый вызов macro-функции, в которой правые части уравнений имеют другое содержимое. Тогда как для отмены macro-определения достаточно произвести соответствующий вызов функции macro(Xp = Yp). Следующий простой фрагмент иллюстрирует вышесказанное:

> restart; macro(x = x*sin(x), y = a*b+c, z = 56):

> HS:= proc(x) local y; y:= 42: y*x^3 end proc:

> macro(HS=AGN, x = x, y = 47, z = 99): map(HS, [x, y, z]);

[AGN(x), AGN(47), AGN(99)] > HS:= proc(x) local y; y:= 42: y*10^3 end proc:

> map(HS, [x, y, z]); ⇒ [42000, 42000, 42000]

> macro(HS=AGN, x = x, y = 47, z = 99): map(HS, [x, y, z]);

[AGN(x), AGN(47), AGN(99)]

> restart: HS:= proc(x) local y; y:= 42: y*x^3 end proc: HS(1999); 335496251958

> macro(HS=AGN): [AGN(1999), HS(1999)];

[AGN(1999), AGN(1999)]

> alias(AGN=HS): [AGN(1999), HS(1999)];

Warning, alias or macro HS defined in terms of AGN

[335496251958, AGN(1999)]

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

Определение переменной в текущем документе (ТД) является глобальным, т.е. доступным любому другому ТД в течение текущего сеанса работы с ядром пакета. Сказанное не относится к режиму параллельного сервера, когда все загруженные документы являются независимыми. Режим параллельного сервера детально рассмотрен в [9-12]. При этом, определение считается сделанным только после его реального вычисления. После перезагрузки пакета все определения переменных и пользовательских функций/процедур (отсутствующих в библиотеках, логически сцепленных с главной библиотекой пакета) теряются, требуя нового переопределения. Без перезагрузки пакета этого можно добиться по предложению restart, приводящему все установки ядра пакета в исходное состояние (очистка РОП, отмена всех сделанных ранее определений, выгрузка всех загруженных модулей и т.д.), либо присвоением идентификаторам переменных невычисленных значений вида Id:='Id'. Следующий простой фрагмент иллюстрирует вышесказанное:

> x:= 19.42: y:= 30.175: Grodno:= sin(x) + cos(y); ⇒ Grodno := 0.8639257079

> restart; Grodno:= sin(x) + cos(y); ⇒ Grodno := sin(x) + cos(y)

> G:= proc() nargs end proc: G(42, 47, 67, 62, 89, 96); ⇒ 6

> G:= 'G': G(42, 47, 67, 62, 89, 96); ⇒ G(42, 47, 67, 62, 89, 96)

Из фрагмента хорошо видно, что ранее сделанное определение Grodno-переменной отменяется после выполнения restart-предложения. Выполнение restart-предложения следует лишь на внешнем уровне ТД и не рекомендуется внутри ряда его конструкций (функции, процедуры и др.) во избежание возникновения особых и аварийных ситуаций, включая “зависание” пакета, требующее перезагрузки ПК. При этом, следует иметь в виду, что освобождаемая в этом случае память не возвращается операционной среде, а присоединяется к собственному пулу свободной памяти пакета. Поэтому при необходимости получения максимально возможной памяти для решения больших задач пользователю рекомендуется все же производить перезагрузку пакета в Windows-среде. Тогда как второй способ отмены определенности для переменных более универсален. В книге [103] и в прилагаемой к ней Библиотеке представлены средства, обеспечивающие возможность восстановления из процедур исходного состояния объектов. Например, вызов процедуры prestart() очищает все переменные, определенные в текущем сеансе, исключая пакетные переменные.

Предложение присвоения. Идентификатору может быть присвоено любое допустимое Maple-выражение, делающее его определенным; в противном случае идентификатор называется неопределенным, результатом вычисления которого является символьное представление самого идентификатора, что весьма прозрачно иллюстрирует следующий простой пример:

> macro(Salcombe = Vasco): Eesti:= 19.95: Vasco:= Noosphere: Tallinn:= 20.06:

> TRG:= sqrt(Lasnamae*(Eesti + Tallinn)/(Salcombe + Vasco)) + `Baltic Branch`;

Lasnamae

TRG := 4.472694937 + Baltic Branch

Noosphere

Присвоение идентификатору определенного или неопределенного значения производится посредством традиционного (:=)-оператора присвоения вида А:= В, присваивающего левой А-части В-значение. При этом, в качестве левой А-части могут выступать простой идентификатор, индексированный идентификатор или идентификатор функции с аргументами. Точнее, присвоение А-части В-значения корректно, если A имеет assignable-тип, т.е. type(A, 'assignable'); ⇒ true. Вычисленное (или упрощенное) значение В-части присваивается идентификатору А-части.

Оператор присваивания допускает возможность множественного присваивания и определяется конструкциями следующего простого вида:

Id1, Id2, …, Idn := <Выражение_1>, <Выражение_2>, …, <Выражение_n>

При этом, при равном количестве компонент правой и левой частей присвоения производятся на основе взаимно-однозначного соответствия. В противном случае инициируются ошибочные ситуации "Error, ambiguous multiple assignment" либо "Error, cannot split rhs for multiple assignment". Следующий фрагмент иллюстрирует случаи множественного присваивания:

> A, B, C:= 64, 59:

Error, ambiguous multiple assignment

> V, G, S, Art, Kr, Arn:= 64, 59, 39, 17, 10, 44: [V, G, S, Art, Kr, Arn];

[64, 59, 39, 17, 10, 44]

> x, y, z, t, h:= 2006: [x, y, z, t, h];

Error, cannot split rhs for multiple assignment

[x, y, z, t, h]

Примеры фрагмента достаточно прозрачны и особых пояснений не требуют. Сам принцип реализации множественного присваивания также достаточно прост. Вместе с тем, языком не поддерживаются уже достаточно простые конструкции множественного присваивания, что иллюстрируют первый и последний примеры фрагмента.

Между тем, в ряде случаев возникает необходимость назначения того же самого выражения достаточно длинной последовательности имен или запросов функций. Данная проблема решается оператором `&ma`, который имеет идентичный с оператором `:=` приоритет. Оператор `&ma` имеет два формата кодирования, а именно: процедурный и операторный форматы:

&ma('x', 'y', 'z', ..., <rhs>) и ('x', 'y', 'z', ...) &ma (<rhs>)

В общем случае, в обоих случаях в конструкции lhs &ma rhs элементы lhs должны быть закодированы в невычисленном формате, т.е. в апострофах ('). Исключение составляет лишь первый случай присвоения. Кроме того, в операторном формате, левая часть lhs должна быть закодирована в скобках. Кроме того, если правая часть rhs удовлетворяет условию type(rhs, {'..', '<', ` <= `, '.', '*', '^', '+', '='}) = true, то правая часть должна также кодироваться в скобках. Наконец, если необходимо присвоить NULL-значение (т. е. ничего) элементам левой части lhs, то в качестве правой части rhs кодируется _NULL-значение. Успешный вызов процедуры `&ma` или применения оператора &ma возвращает NULL-значение, т. е. ничего с выполнением указанных присвоений. В целом ряде приложений оператор/процедура &ma представляются достаточно полезными [103]. Ниже приведен ряд примеров на применение оператора &ma: