Смекни!
smekni.com

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

> P:= proc() local k; options remember; sum(args[k], k= 1 .. nargs) end proc: # (1)

> [P(10, 17, 39, 44, 59, 64), P(96, 89, 67, 62, 47, 42), P(11, 6, 98, 445, 2006)]: op(4, eval(P)); table([(11, 6, 98, 445, 2006) = 2566, (96, 89, 67, 62, 47, 42) = 403, (10, 17, 39, 44, 59, 64) = 233])

> P(42, 47, 67, 89, 96):= 2006: P(56, 51, 31, 2, 9):= 2500: op(4, eval(P)); # (2) table([(42, 47, 67, 89, 96) = 2006, (11, 6, 98, 445, 2006) = 2566, (96, 89, 67, 62, 47, 42) = 403,

(56, 51, 31, 2, 9) = 2500, (10, 17, 39, 44, 59, 64) = 233])

> T:= op(4, eval(P)): T[(42, 47, 67, 89, 96)]:= evaln(T[(42, 47, 67, 89, 96)]): op(4, eval(P)); table([(11, 6, 98, 445, 2006) = 2566, (96, 89, 67, 62, 47, 42) = 403, (56, 51, 31, 2, 9) = 2500,

(10, 17, 39, 44, 59, 64) = 233])

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

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

> GS:=proc(x) evalf(1/x,3) end proc: GS(0):=infinity: map(GS, [10,0,17]); ⇒ [0.100, ∞, 0.0588] > op(4, eval(GS)); ⇒ table([0 = ∞])

Данный фрагмент иллюстрирует еще один важный момент, связанный с процедурами, а именно. С каждой процедурой независимо от наличия в ее определении remember-параметра ассоциируется remember-таблица, сохраняющая историю присвоений по конструкциям Proc(ФА):= <Значение> и assign('Proc(ФА)', <Значение>), где Proc – процедура, определенная любым допустимым способом, и ФА - ее фактические аргументы, на которых она принимает указанное значение. Таким образом, remember-таблица для Procпроцедуры может создаваться двумя способами, а именно:

(1) Proc := proc(...) option remember; ... end proc {:|;}

(2) Proc := proc(...) ... end proc: Proc(ФА) := <Значение> {:|;}

В обоих случаях с Proc-процедурой Maple ассоциирует remember-таблицу, однако работу с ней организует по-разному. В первом случае remember-таблица будет содержать лишь определенные по вышеуказанным конструкциям входы и не обновляться вызовами Proc-процедуры, тогда как во втором случае каждый вызов Proc-процедуры соответствующим образом модифицирует таблицу, сохраняя историю уникальных вызовов процедуры. Следующий простой фрагмент иллюстрирует вышесказанное:

> G:= proc(x) x end proc: [assign('G(42)', 647), assign('G(47)', 59), assign('G(67)', 39)]:

> G1:= x -> x: [assign('G1(42)', 64), assign('G1(47)', 59), assign('G1(67)', 39)]:

> define(G2, G2(x::numeric) = x): [assign('G2(42)', 64), assign('G2(47)', 59), assign('G2(67)',

39)]: op(4, eval(G)), op(4, eval(G1)), op(4, eval(G2)); table([67 = 39, 42=64, 47 = 59]), table([67 = 39, 42=64, 47 = 59]), table([67 = 39, 42=64, 47 = 59]) > P:= proc(x) option remember; x^10 end proc: for k to 3 do P(k) end do:

> P1:= proc(x) x^10 end proc: P1(42):= 64: P1(47):= 59: for k to 5 do P1(k) end do: op(4, eval(P)), op(4, eval(P1)); ⇒ table([1 = 1, 2 = 1024, 3 = 59049]), table([42 = 64, 47 = 59])

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

3.5. Механизмы возврата Maple-процедурой результата ее вызова

В результате вызова стандартным является возврат результата выполнения процедуры через значение последнего предложения ее тела. Однако, Maple-язык поддерживает еще три основных механизма возврата результата вызова процедуры: через фактический аргумент, функцию RETURN (return-предложение) и ERRОR-функцию (error-предложение). В случае возникновения ошибочной ситуации в период выполнения процедуры производится аварийный выход из нее с выводом соответствующего сообщения. В отсутствие ошибочных ситуаций предварительно вычисленная процедура с Proc-именем (идентификатор, которому присвоено определение процедуры) вызывается подобно функции по конструкции следующего формата кодирования:

Proc(<Фактические аргументы>)

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

RETURN(<Последовательность выражений>) return <Последовательность выражений> {:|;}

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

> AG:= proc(x::integer, y::float,R) `if`(x*y>R, x, y) end proc: AG(64, 51.6, 350); ⇒ 64

> SV:= proc(x, L::list) member(x, {op(L)}) end proc: SV(10, [64, 59, 10, 39, 17]); ⇒ true

> MV:=proc(x, L::list) local k, H; assign(H=[]), seq(`if`(x=L[k], assign('H'=[op(H), k]),

NULL), k=1 .. nops(L)); H end proc: MV(95, [57, 95, 52, 95, 3, 98, 32, 10, 95, 37, 95, 34, 23,

95]); ⇒ [2, 4, 9, 11, 14] > MM:=(x,L::list) -> op([seq(`if`(x=L[k], RETURN([k, {L[k]}]), NULL), k=1..nops(L)), false]): > k:=56: MM(2006, [57, 52, 3, 1999, 32, 10, 1995, 37, 180, 23, 1.0499, 2006]), k; ⇒ [12, {2006}], 12

> MM(1942, [57, 52, 3, 98, 32, 10, 95, 37, 96, 34, 23, 97, 45, 42, 47, 67, 89, 96]); ⇒ false > TP:= proc() local m,n,k; (m, n) &ma 0; for k to nargs do `if`(type(args[k], 'numeric'), assign('m', m+1), assign('n', n+1)) end do; return [`Аргументы:`, [m, `Числовые`], [n, `Нечисловые`]]; end proc: TP(64, 59., 10/17, "RANS", Pi, TRG);

[Аргументы:, [3, Числовые], [3, Нечисловые]]

> VS:= proc() local k, T; assign(T=array(1..nargs+1, 1..2)), assign(T[1,1]=Argument, T[1,2] = Type); for k to nargs do T[k+1, 1]:=args[k]; T[k+1,2]:=whattype(args[k]) end do: return eval(T) end proc: VS(RANS, "IAN", 2006, F(x), n..p, array(1..3, [10, 17, 39]));

[10 17 39Argument"IAN"RANS2006n,F .. ( )xp, ] functionintegersymbolstringarrayType.. 

Первые три примера фрагмента представляют простые процедуры AG, SV и MV, назначение первой из которых легко усматривается из ее определения, а две другие возвращают соответственно результат тестирования и список номеров позиций вхождения хэлемента в заданный L-список. Все три процедуры возвращают результат стандарным способом через последнее предложение тела процедуры. Остальные примеры фрагмента иллюстрируют возврат результата процедуры RETURN-функцией либо return-предложением.

Процедура ММ возвращает список с номером позиции первого вхождения х-элемента в L-список и сам элемент, в противном случае возвращается false-значение. Процедура для возврата результата вызова использует как стандартный метод, так и RETURN-функцию. При этом, рекомендуется обратить внимание на реализацию процедуры однострочным экстракодом. Процедура ТР возвращает результат анализа получаемых при ее вызове фактических аргументов в разрезе числовых и нечисловых с идентификацией количества аргументов обоих типов. Процедура VS возвращает таблицу, первый столбец которой содержит передаваемые процедуре вычисленные фактические аргументы, тогда как второй - их типы. Одним из достоинств использования функции RETURN является возможность эффективного возврата значений локальных переменных из целого ряда важных вычислительных конструкций, а также обеспечение гибкой возможности избирательности возврата результатов вызова пользовательских процедур. Тогда как предложение return имеет существенно меньшие выразительные возможности по представлению вычислительных алгоритмов в среде Maple-языка.

Следует отметить, что, начиная с Maple 6, разработчики объявили о том, что RETURNфункция является устаревшим средством (obsolete) и сохранена для обеспечения обратной совместимости процедур, разработанных в предыдущих релизах пакета. При этом, настоятельно рекомендуя использование именно return-предложения. Наш опыт работы с Maple говорит совершенно об обратном. Использование RETURN-функции во многих случаях более предпочтительно, позволяя создавать эффективные выходы из вычислительных конструкций, прежде всего, в однострочных экстракодах. Ниже на этом моменте акцентируем несколько больше внимания.

В общем случае функция RETURN(V1,V2 ,..., Vn), где в качестве фактических аргументов могут выступать произвольные Maple-выражения, предварительно вычисляемые, может не только возвращать конкретные результаты вычисления Vk-выражений, связанных со спецификой тела процедуры, но и возвращать в определенных условиях вызов процедуры невычисленным. Для этих целей, как правило, используется конструкция вида RETURN('Proc(args)'), где Proc – имя (идентификатор) процедуры. Библиотечные процедуры Maple в случае некорректного либо прерванного вызова возвращают FAILзначение, если нецелесообразно возвращать вызов процедуры невычисленным. Следующий простой фрагмент иллюстрирует вышесказанное:

> LO:= proc() local k; for k to nargs do if whattype(args[k]) <> 'float' then return 'LO(args)' end if end do end proc: LO(64, 59, 39.37, 19.81, 19.83, 10, 17, G, S); LO(64, 59, 39.37, 19.81, 19.83, 10, 17, G, S)

> [sqrt(10), sin(17), ln(gamma), exp(Pi)]; ⇒ [ 10, sin(17), ln( )γ , eπ ]

В данном фрагменте LO-процедура в случае обнаружения среди переданных ей фактических аргументов выражения типа, отличного от float, сразу же осуществляет выход по return-предложению с возвращением своего вызова невычисленным. Тогда как второй пример иллюстрирует возврат невычисленных вызовов базовых функций Maple-языка.