Смекни!
smekni.com

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

> P:= proc(x, y, z, $) `+`(args) end proc: P(64, 59, 39), P(64, 59); # Maple 10 ⇒ 162, 123 > P(64, 59, 39, 10, 17);

Error, invalid input: 5 arguments passed to P but only 3 positional parameters specified

> lasterror;

"invalid input: %1 arguments passed to %2 but only %3 positional parameters specified" > P:= proc(x, y, z, $) `+`(args) end proc: P(64, 59, 39), P(64, 59); # Maple 6 – 9 Error, `$` unexpected

> lasterror; ⇒ lasterror

Тогда как в предыдущих релизах 6 – 9 данная новация вызывает ошибочную ситуацию уже на уровне синтаксиса, не отображаясь в lasterror-переменной. Принципиально, данная новация не столь уж существенна, добавляя пакету несовместимость «сверху-вниз» (в принципе, каноны программирования это допускают, но все же). Тем более, что контроль за передаваемыми процедуре фактическими аргументами легко осуществляется программно и на основе сути реализуемого ею алгоритма с использованием nargs-переменной.

Дополнительно к двум процедурным переменным args и nargs, рассмотренным выше, в релизе 10 введен ряд дополнительных процедурных переменных, а именно:

_passed – алиас для переменной args

_params – последовательность продекларированных позиционных аргументов, передан- ных процедуре

_options – последовательность опций в процедуре

_rest – последовательность недекларированных аргументов, переданных процедуре _npassed – алиас для переменной nargs

_nparams – число продекларированных позиционных аргументов, переданных процедуре

_noptions – число опций в процедуре

_nrest – число недекларированных аргументов, переданных процедуре

_nresults - число предполагаемых выходов из процедуры

Смысл их достаточно прозрачен уже из приведенного описания, а детальнее с ними можно ознакомиться по конструкции ?args, тогда как примеры их применения представляет нижеследующий простой фрагмент:

> P:=proc(x,y,z) option remember; `if`(x=1, RETURN(x+y), `if`(y=2, RETURN(z+y), `if`(z=3, RETURN(x+z),NULL))); [[_params],_options,_rest,_nparams,_noptions,_nrest,_nresults]

end proc: P(64, 59, 39); ⇒ [[64, 59, 39], 3, 0, 0, undefined] > P(64,59,39,10,17); ⇒ [[64, 59, 39], 10, 17, 3, 0, 2, undefined] > С:=proc(x,y,z)::integer; if x=1 then return x+y elif y=2 then return z+y elif z=3 then return x+z end if; [[_params], _options, _rest,_nparams, _noptions, _nrest, _nresults] end proc:

> С(64, 59, 39); ⇒ [[64, 59, 39], 3, 0, 0, undefined]

> С(64, 59, 39, 10, 17); ⇒ [[64, 59, 39], 10, 17, 3, 0, 2, undefined]

При программировании процедур вышеперечисленные переменные в ряде случаев могут упрощать программирование, однако порождают несовместимость «сверху-вниз».

3.8. Расширение функциональных средств Maple-языка пакета

Многие встроенные и библиотечные процедуры Maple допускают пользовательские расширения, увеличивающие область применения данных средств. Например, можно определять новые типы и преобразования, расширять диапазон математических функций, обрабатываемых функциями evalf и diff, расширяя тем самым средства главной Maple-библиотеки. Каждое уникальное расширение средства (типа type либо diff) ассоциируется с именем. Это имя определяет имя расширяемого средства, например, для type это – type. Существуют два механизма расширения: классический механизм расширения, используемый в большинстве случаев, и современный механизм расширения, используемый более новыми средствами, например, пакетный модуль TypeTools (начиная с Maple 8), содержащий 5 процедур для расширения множества типов, распознаваемых функцией type пакета, играющей важную роль при типизации объектов пакета.

Классический механизм расширения имеет единственную глобальную область для имен расширения, тогда как современный механизм позволяет именовать расширения в ряде областей имен (иными словами, использование современного механизма предоставляет возможность присваивать имена расширениям, которые будут локальными для процедур или модулей). С вопросами использования современного механизма расширений можно ознакомиться по запросу ?extension, здесь же мы вкратце рассмотрим классический механизм расширений средств пакета, носящий глобальный характер

Все встроенные процедуры и большинство библиотечных процедур, допускающие пользовательские расширения, используют классический механизм, основанный на конкатенации имен, а именно. Расширяемой процедуре name дают новые функциональные возможности, определяя выражение (как правило, процедура) с именем формата `name/new`, где new – имя расширения. Например, новый тип для бинарных выражений (распознаваемый type-функцией) может быть определен процедурой с именем `type/binary`. При этом, вводимые расширения для стандартного средства name должны удовлетворять определенным правилам, которым удовлетворяет данное средство name, и которые отражены в справке по данному средству. Например, при расширении стандартной type-функции процедурой с именем `type/aa` требуется, чтобы она возвращала только значения {true, false}, в противном случае инициируется ошибка с диагностикой "result from type `%1` must be true or false", например:

> `type/aa`:=proc(x::numeric) if x<0 then true elif x>0 then false else FAIL end if end proc:

> type(0, 'aa');

Error, result from type `aa` must be true or false

> lasterror; ⇒ "result from type `%1` must be true or false"

В качестве примера расширения стандартной type-функции определим новый тип color, отсутствующий в пакете текущих релизов и достаточно полезный для большого числа задач, имеющих дело с графическими объектами. Вызов процедуры type(x, 'color') возвращает значение true, если x – имя цвета, процедура либо выражение, которые можно рассматривать в качестве цвета при формировании графического объекта; в противном случае возвращается false-значение. При этом, через глобальную _ColorType-переменную возвращается 2-элементный бинарный список, если вызов процедуры type(x, 'color') возвращает true-значение. Его первый и второй элементы определяют допустимость xвыражения в качестве цвета (0 – нет, 1 – да) при оформлении графического объекта с опцией color = x в случае размерности 2 и 3 соответственно. Если же вызов процедуры возвращает false-значение, то переменная _ColorType возвращается неопределенной. Процедура `type/color` имеет целый ряд полезных приложений, однако ее применение предполагает дополнительную проверку через глобальную переменную _ColorType из-за различий механизмов раскраски для 2- и 3-мерных графических объектов. Ниже приведены исходный текст процедуры `type/color` и примеры ее применения.

global _ColorType;

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

type/float_list := G → `if`(type(G, 'list'),

`if`(member(false, {op map(( type G, , 'float'))}), false true, ), false)

> type([6.4, 5.9, 3.9, 2.6, 17.6, 10.3], 'float_list'); ⇒ true > type([6.4, 5.9, 3.9, 2.6, 17.6, 10.3, 2006], 'float_list'); ⇒ false type/complex1 := proc(Z::anything) local `1` `2` a b c d h t k rm im sv tn, , , , , , , , , , , , ; option `Copyright (C) 2004 by the International Academy of Noosphere. All rights &bsol; reserved.`; assign(`1` = cat "",( convert(interface '( imaginaryunit'), 'string'))), assign(`2` = [cat("*", `1`), cat(`1`, "*"), `1`]);

if map2(search, convert(Z, 'string'), {op(`2`)}) = {false} then false else assign(h = interface(warnlevel), a = normal evalf(( Z))), null interface(( warnlevel = 0)); tn := proc(x) local a; a := convert(x, 'string'); `if`(a[-1] = "." came( [, a 1 .. -2]), x)

end proc ; sv := s → `if`(4 < length( )s and member(s[1 .. 4], {"-1.*" "+1.*", }), s[5 .. -1], s);

d := denom(a); if d = 1 or Search2(convert(d, 'string'), {op(`2`)}) = [ ] then a := convert(normal evalf(( a)), 'string')

else a := convert(expand normal(( evalf(conjugate(d)×numer(a)))), 'string') end if;

a := `if`(member(a[1], {"-" "+", }), a, cat "+",( a)); assign67(b = seqstr '( procname args( )'), t = NULL);

b := b[length(cat "`type/convert1`", "(",( convert(Z, 'string'))) + 1 .. -2]; if b = "" then t := 'realnum' else t := came( sub_1([seq(k = "realnum", k = ["fraction" "rational", ])], b[2 .. -1]))

end if;

c := Search2(a, {"-" "+", }); if nops( )c = 1 then a := sub_1([`2`[1] = NULL, `2`[2] = NULL], a); null interface(( warnlevel = h)), type(tn(came(sv a( ))), t)

else assign(rm = "", im = "" ' ', b =

[seq(a[c k[ ] .. c[k + 1] − 1], k = 1 .. nops( )c − 1), a[c[-1] .. -1]])

; for k to nops(b) do if Search2(b k[ ], {`2`[1], `2`[2]}) = [ ] then rm := cat(rm, b k[ ]) else im := cat(im, sub_1 [( `2`[1] = NULL, `2`[2] = NULL], b k[ ]))

end if end do; try `if`(im = "" RETURN(, false), assign('rm' = came(sv rm( )), 'im' = came(sv im( )))) catch : RETURN(null interface(( warnlevel = h)), false) end try ; null interface(( warnlevel = h)),

`if`(map(type, {tn rm( ), tn im( )}, t) = {true}, true false, )

end if

end if

end proc

> type((a + I)*(a - a*I + 3*I), complex1(algebraic)); ⇒ true

> type(a + sqrt(8)*I, complex1({symbol, realnum})); ⇒ true

> map(type, [-3.65478, 64, 2006, -1995, 10/17], 'complex1'); ⇒ [false, false, false, false, false]

> type(2004, complex1(numeric)); ⇒ false

> type([a, b] - 3*I, complex1({realnum, list})); ⇒ true

> type(-3.67548, 'complex'), type(-3.67548, 'complex1'); ⇒ true, false > assume(a, 'integer'); type((a-I)*(a+I), complex(algebraic)), type((a-I)*(a+I), complex1(algebraic)); ⇒ true, false

> type((10 - I)*(10 + I), 'complex'), type((10 - I)*(10 + I), 'complex1'); ⇒ true, false

> type(8 + I^2, complex(algebraic)), type(8+I^2, complex1); ⇒ true, true

> type(8 + I^2, complex1(algebraic)), type(8 + I^2, 'complex1'); ⇒ false, false

> type(64,'complex'),type(64,'complex1'),type((3+4*I)/(5+6*I),'complex1'); ⇒ true, false, true convert/uppercase := proc(S::{string, symbol}) local k h t G R, , , , ; assign(G = "", R = convert(S, 'string'));

for k to length(R) do G := cat(G, op([assign(' 't = op convert(( R k[ ], 'bytes'))), `if`( t ≤ 255 and 224 ≤ t or t ≤ 122 and 97 ≤ t, convert [( t − 32], 'bytes'), `if`(t = 184, "¨", R[k]))])) end do;

convert(G, whattype(S))

end proc

> convert("Russian Academy of Natural Sciences - 20.09.2006", 'uppercase');

"RUSSIAN ACADEMY OF NATURAL SCIENCES - 20.09.2006" &ma := proc() op map( (assign, [seq(args[ ]k , k = 1 .. nargs − 1)],

`if`(args -1[ ] = _NULL NULL, , args -1[ ])))

end proc

> x, y, z:= 64;

Error, cannot split rhs for multiple assignment

> &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