Для отмены значений имен, имеющих protected-атрибут, может оказаться достаточно полезной и процедура Unassign('n1', 'n2', ...), возвращающая NULL-значение и отменяющая назначения для имен {'n1', 'n2', ...}, закодированных в невычисленном формате. Ее исходный текст представляется однострочным экстракодом следующего вида: Unassign := ( ) → `if`(nargs = 0, NULL, op([unprotect(args), unassign(args)]))
Приведем примеры применения процедур стандартной unassign и нашей Unassign:
> x, y, z, t, h:= 42, 47, 67, 89, 95: protect('x','y','z', 't', 'h'); > unassign('x','y','z', 't', 'h'); Error, (in assign) attempting to assign to `x` which is protected > x, y, z, t, h; ⇒ 42, 47, 67, 89, 95 > Unassign('x','y','z', 't', 'h'); > x, y, z, t, h; ⇒ x, y, z, t, h > Unassign(); > unassign(); Error, (in unassign) argument expected |
Как следует из приведенного фрагмента, наша процедура Unassign в отличие от стандартной корректно обрабатывает особую ситуацию «отсутствие фактических аргументов», возвращая и в этом случае NULL-значение.
В целях защиты идентификаторов от возможных модификаций их определений (назначений) им присваивается protected-атрибут, делающий невозможной какую-либо модификацию указанного типа. Большинство пакетных идентификаторов имеют protectedатрибут, в чем легко убедиться, применяя к ним attributes-функцию, кодируемую в следующем формате: attributes(<Идентификатор>)
и возвращающую значения атрибутов заданного идентификатора, в частности атрибута protected. Если идентификатору не приписано каких-либо атрибутов, то вызов на нем attributes-функции возвращает NULL-значение, т.е. ничего. Для защиты от модификации либо снятия защиты используются процедуры protect и unprotect Maple-языка соответственно, кодируемые в следующем простом формате:
{protect|unprotect}(<Идентификатор_1>, <Идентификатор_2>, ...)
Следующий весьма простой фрагмент Maple-документа иллюстрирует вышесказанное:
> protect(AV_42); attributes(AV_42); ⇒ protected
> unassign(AV_42);
Error, (in assign) attempting to assign to `AV_42` which is protected > AV_42:= 64:
Error, attempting to assign to `AV_42` which is protected
> unprotect(AV_42); attributes(AV_42); AV_42:= 64; ⇒ AV_42 := 64
Следует при этом отметить, что действие protect-процедуры не распространяется на глобальные предопределенные переменные Maple, значения которых можно модифицировать согласно условиям пользователя. Такая попытка вызывает ошибочную ситуацию:
> map(attributes, [Digits, Order, printlevel]); protect('Digits'); protect('Order'); protect('printlevel'); ⇒ []
Error, (in protect) an Environment variable cannot be protected
Error, (in protect) an Environment variable cannot be protected
Error, (in protect) an Environment variable cannot be protected
Хотя по unprotect-процедуре отменяется protected-атрибут любого идентификатора, однако для пакетных идентификаторов этого (по целому ряду причин, здесь не рассматриваемых) делать не рекомендуется.
В целом ряде случаев в качестве весьма полезных средств могут выступать две встроенные функции со следующими форматами кодирования: unames() и anames({ |<Тип>}), возвращающие последовательности соответственно неопределенных и определенных идентификаторов (как пользовательских, так и пакетных), приписанных текущему Maple-сеансу. При этом, для случая anames-функции можно получать подборку определенных идентификаторов, значения которых имеют указанный Тип. Следующий фрагмент иллюстрирует результат вызова указанных выше функций:
> restart; unames(); identical, anyfunc, equation, positive, Integer, restart, radical, And, gamma, neg_infinity, none, default, nonposint, relation, odd, infolevel, indexable, algebraic, SFloat, RootOf, TABLE, float, real_to_complex, embedded_real, vector, _syslib, realcons, name, assign, INTERFACE_GET, ... > restart: SV:= 39: GS:= 82: Art:= sin(17): Kr:= sqrt(10): AV:= 64: anames(); sqrt/primes, type/interfaceargs, GS, sqrt, AV, csgn, interface, type/SymbolicInfinity, Art, sin, SV, Kr > anames('integer'); # Maple 8 sqrt/primes, GS, Digits, printlevel, Order, AV, SV > anames('environment'); Testzero, UseHardwareFloats, Rounding, %, %%%, Digits, index/newtable, mod, %%, Order, printlevel, Normalizer, NumericEventHandlers > SV:= 39: GS:= 82: `Art/Kr`:= sin(17): Kr:= sqrt(10): _AV:= 64: anames('user'); # Maple 10 Kr, SV, GS > anames('alluser'); ⇒ Kr, SV, GS, _AV, Art/Kr |
При этом, unames-функция была вызвана в самом начале сеанса работы с пакетом и возвращаемый ею результат представлен только начальным отрезком достаточно длинной последовательности пакетных идентификаторов. Что касается anames-функции, то она в качестве второго необязательного аргумента допускает тип, идентификаторы с которым будут ею возвращаться. При этом, дополнительно к типу и в зависимости от релиза в качестве второго аргумента допускается использование таких параметров как user, environment, alluser, назначение которых можно вкратце охарактеризовать следующим образом. Параметр environment определяет возврат имен предопределенных переменных текущего сеанса пакета, параметр user (введенный, начиная с Maple 9) определяет возврат имен, определенных пользователем, тогда как параметр alluser (введенный, начиная с релиза 10) аналогичен по назначению предыдущему параметру user, но без фильтрации имен пользователя, содержащих прямой слэш «/» и префикс «_» (подчеркивание).
В ряде случаев требуется на основе определенного выражения определить имя (имена), которым в текущем сеансе было присвоено данное выражение. Данная задача решается нашей процедурой nvalue, базирующейся на стандартной процедуре anames и использующей некоторые особенности пакета. Ниже эта процедура будет представлена более детально, здесь же мы приведем лишь фрагмент ее применения, а именно:
> a:= 63: b:= 63: c:= "ransian63": c9:= "ransian63": d:= table([1=63, 2=58, 3=38]): L:= [x, y, z]: assign('h'=`svegal`): t47:= 19.42: t42:= 19.42: R:= a+b*I: B:= a+b*I: Z:= (a1+b1)/(c1+d1): f:=cos(x): g:=proc() `+`(args)/nargs end proc: r:=x..y: m:=x..y: n:= x..y: Lasnamae:= NULL: > Tallinn:=NULL: Grodno:= NULL: Vilnius:= NULL: Moscow:= NULL: map(nvalue, [63, "ransian63", table([1=63,2=58,3=38]), svegal, 19.42, [x,y,z], a+b*I, (a1+b1)/(c1+d1), cos(x), proc () `+`(args)/nargs end proc, x..y]), nvalue(); ⇒ {a, b}, {c9, c}, {d}, {h}, {t47,t42}, {L}, {R,B}, {Z}, {f}, {g}, {m, r, n}, {Tallinn, Grodno, Vilnius, Moscow, Lasnamae}
Важным средством управления вычислениями и преобразованиями в среде Maple-языка является assume-процедура и ряд сопутствующих ей средств. Процедура имеет следующие три формата кодирования:
assume(x1, p1, x2, p2, ...) assume(x1::p1, x2::p2, ...) assume(x1p1, x2p2, ...)
и позволяет наделять идентификаторы (переменные) или допустимые Maple-выражения xj заданными свойствами pj, т.е. устанавливать определенные свойства и соотношения между ними. Третий формат процедуры определяет соотношения, налагающие свойство pj на выражение xj. Например, простейшие, но весьма часто используемые вызовы assume(x >= 0) процедуры, определяют для некоторой х-переменной свойство быть неотрицательной действительной константой. Наделяемое по assume-процедуре свойство не является пассивным и соответствующим образом обрабатывается Maple-языком пакета при выполнении вычислений либо преобразований выражений, содержащих переменные, наделенные подобными свойствами. Тестировать наличие приписанного х-переменной свойства можно по вызову процедуры about(x), тогда как наделять х-переменную дополнительными свойствами можно по вызову процедуры additionally(x, Свойство). Следующий фрагмент иллюстрирует вышесказанное:
> assume(x >= 0): map(about, [x, y, z]); ⇒ [ ] Originally x, renamed x~: is assumed to be: RealRange(0, infinity) y: nothing known about this object z: nothing known about this object > assume(a >= 0): A:= sqrt(-a): assume(a <= 0): B:= sqrt(-a): [A, B]; ⇒ [ a~ I,> simplify(map(sqrt, [x^2*a, y^2*a, z^2*a])); ⇒ [x~ −a~ I, y2 a~, z2 a~ ] > additionally(x, 'odd'): about(x); Originally x, renamed x~: is assumed to be: AndProp(RealRange(0, infinity), LinearProp(2, integer, 1)) > map(is, [x, y, z], 'odd', 'posint'); ⇒ [true, false, false] > assume(y, 'natural'): map(is, [x, y], 'nonnegative'); ⇒ [true, true] > unassign('x'): about(x); x: nothing known about this object > assume(y, {y >= 0, y < 64, 'odd'}): about(y); Originally y, renamed y~: is assumed to be: {LinearProp(2,integer,1), 0 <= y, y < 64} > hasassumptions(y); ⇒ true | −a~ ] |
Из примеров данного фрагмента, в частности, следует, что переменная с приписанным ей свойством выводится помеченной символом тильды (∼), а по about-процедуре выводится информация о всех приписанных переменной свойствах либо об их отсутствии. Один из примеров фрагмента иллюстрирует влияние наличия свойства положительной определенности переменной на результат упрощения содержащего ее выражения. В другом примере фрагмента иллюстрируется возможность определения для переменной множественности свойств, определяемых как поддерживаемыми языком стандартными свойствами, так и допустимыми отношениями для переменной. При этом, вызов процедуры hasassumptions(x) возвращает true, если на x-выражение было наложено какое-либо соотношение, и false в противном случае.
Режим идентификации assume-переменных определяется showassumed-параметром процедуры interface, принимающим значение {0|1 (по умолчанию)|2}: 0 - отсутствует идентификация, 1 - переменные сопровождаются знаком тильды и 2 - все такие переменные перечисляются в конце выражений, как это иллюстрирует следующий фрагмент:
> assume(V >= 64): assume(G >= 59): S:= V+G; interface(showassumed=0); V + G;
S := V~ + G~
V + G
> assume(Art >= 17, Kr >= 10): interface(showassumed=2): S^2 + (Art + Kr)^2;
S2 + (Art + Kr)2
with assumptions on Art and Kr