Смекни!
smekni.com

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

> P:= proc()::float; `+`(args)/nargs end proc: P(64, 59, 39, 10, 17, 44); ⇒ 233/6

> kernelopts(assertlevel = 2): P(64, 59, 39, 10, 17, 44); Error, (in P) assertion failed: P expects its return value to be of type float, but computed 233/6

> lasterror;

"assertion failed: %1 expects its return value to be of type %2, but computed %3"

> P1:= proc()::float; local conv; conv:= proc(a::anything, b::anything) if a = NULL then b else convert(b, a) end if end proc; conv(op(8, eval(procname)), `+`(args)/nargs) end proc; P1 := proc()::float; local conv; conv := proc(a anything:: , b anything:: ) if a = NULL then b else convert(b a, ) end if

end proc ; conv(op(8, eval(procname)), `+`(args)/nargs) end proc

> P1(64, 59, 39, 10, 17, 44); ⇒ 38.8333333300

P := proc()::`+`; op(8, eval('procname'))(args)/nargs end proc

> 6*P(64, 59, 39, 10, 17, 44); ⇒ 233 P2 := proc()::proc() `if`(type(nargs, 'odd'), `+`, `*`) end proc; eval(op 8,( eval 'procname'( )))(args)(args nargs)/

end proc

> P2(42, 47, 67, 89, 95), P2(42, 47, 67, 89, 95, 62); ⇒ 68, 11555161030

Фрагмент содержит подпроцедуру conv, результат вызова которой обеспечивает конвертирование возвращаемого процедурой Р1 выражения в тип, заданный после заголовка процедуры. Возможно, в некоторых случаях такой прием может оказаться полезным. В частности, кодировать после заголовка процедуры Р можно любое корректное Maple-выражение, доступное внутри процедуры по вызову op(8, eval(Р)), что предоставляет целый ряд дополнительных возможностей при программировании приложений, как это иллюстрируют две последние процедуры Р и Р2 фрагмента.

Последний механизм возврата результатов вызова процедуры связан с особыми и ошибочными ситуациями, возникающими в процессе ее выполнения. Любая ошибочная ситуация, возникшая в момент передачи процедуре фактических аргументов либо в процессе ее выполнения, вызывает прекращение выполнения процедуры с возвратом соответствующего диагностического сообщения, которое в целом ряде случаев может недостаточно адекватно отражать возникшую ситуацию (см. прилож. 1 [12]). Однако, наряду с такого типа ситуациями, обрабатываемыми Maple автоматически, пользователь имеет возможность как производить обработку ситуаций, определяемых спецификой вызываемой процедуры, так и в определенной мере перехватывать обработку ошибочных ситуаций, стандартно обрабатываемых пакетом. В следующем разделе рассматриваются средства обработки ошибочных ситуаций, имеющих особый смысл именно для процедурных и модульных объектов.

3.6. Средства обработки ошибочных и особых ситуаций в Maple-языке пакета

В процессе вычисления Maple-конструкций возможно появление особых и аварийных ситуаций, которые в большинстве случаев требуют специальной обработки во избежание серьезного нарушения всего вычислительного процесса. Идентифицируемые пакетом ситуации такого рода возвращаются в предопределенную lasterror-переменную, значение которой определяет последнюю обнаруженную в текущем сеансе ошибку и доступно текущему сеансу для необходимой обработки возникшей ситуации. Значение lasterror-переменной определяется только в момент возникновения ошибочной ситуации, а сразу же после загрузки пакета она является неопределенной. К lasterror-переменной непосредственно примыкает и tracelast-функция, обеспечивающая вызов последней ошибочной ситуации из стэка ошибок пакета. При этом, между ними имеется принципиальное различие, а именно: через lasterror-переменную возвращается ошибочная диагностика, обрабатываемая функциональными средствами языка, тогда как tracelast-функция инициирует вызов последней ошибочной ситуации, если она не была удалена из стэка ошибок. Значение lasterror-переменной имеет string-тип. Следующий простой пример иллюстрирует применение обоих указанных средств Maple-языка, предназначенных для обработки ошибочных ситуаций:

> read("D:/Academy/UserLib6789/Common/HelpBase/SveGal.mws");

Error, unable to read `D:/Academy/UserLib6789/Common/HelpBase/SveGal.mws`

> lasterror; ⇒ "unable to read `%1`"

> tracelast;

Error, unable to read `D:/Academy/UserLib6789/Common/HelpBase/SveGal.mws`

Для обработки ошибочных ситуаций в ранних релизах совместно с lasterror-переменной использовалась функция traperror(V1,V2, ..., Vn), по которой возвращается сообщение, соответствующее первой встреченной ошибочной ситуации в выражениях Vk (k = 1..n). При этом, каждый вызов функции traperror отменяет определение предопределенной переменной lasterror. Это же производится и по traperror()-вызову. Если же при вызове функции traperror не обнаружено особых ситуаций, то она возвращает упрощенные/вычисленные выражения, входящие в состав ее фактического аргумента. В случае указания в качестве фактического аргумента последовательности выражений только первому, вызвавшему ошибочную ситуацию, приписывается соответствующее диагностическое сообщение. Данное сообщение может использоваться совместно с lasterror-информацией для организации обработки особых и ошибочных ситуаций, возникающих в процессе вычислений в документе или Maple-процедуре. Следующий простой пример иллюстрирует вышесказанное:

> VS:=0: AG:=15.04: if (traperror(AG/VS)=lasterror) then T:=AG/10.17 end if: [T, lasterror];

[1.478859390, "numeric exception: division by zero"]

В данном примере на основе вызова traperror(AG/VS) и lasterror обрабатывается особая ситуация “деление на нуль”, в результате чего производится устранение данной ситуации путем перехода к вычислению другого выражения. При этом, следует обратить внимание на то обстоятельство, что при возникновении ошибочной ситуации в вычисляемом по traperror-функции выражении сообщение о ней поглощается функцией, не отражаясь в документе. Большинство серьезных особых и аварийных ситуаций идентифицируется предопределенной lasterror-переменной, поэтому совместное использование указанных средств может оказаться достаточно эффективным. При этом, следует иметь в виду, что ряд возникающих особых ситуаций не обрабатывается функцией traperror. В общем же случае, следующие ошибочные и особые ситуации не обрабатываются traperror:

* interrupted (прерванное вычисление)

* assertion failed (генерируется при активном ASSERT-механизме)

* out of memory (недостаток па-мяти),

* stack overflow (переполнение стэка) * object too large (объект слишком велик).

Это объясняется невозможностью восстановления на момент возникновения указанных ситуаций. При этом, следует иметь в виду, что вызов traperror(V) не связывает с V-выражением особой ситуации типа “деление на нуль”, если в качестве V-аргумента выступает конструкция следующего вида {V/0|V/(a-a)|V/(a*0)}, т.е. если знаменатель дроби тождественно равен нулю, а не принимает нулевого значения в результате вычисления (присвоения) или упрощения выражения. Следующий фрагмент иллюстрирует сказанное:

> x:= 64: y:= 0: T:= traperror(x/(a - a)): [lasterror, T];

["numeric exception: division by zero", T]

Error, numeric exception: division by zero

> x:= 64: y:= 0: T:=traperror(x/(a*0)): [lasterror, T];

["numeric exception: division by zero", T]

Error, numeric exception: division by zero

> x:= 10: y:= 0: T:= traperror(x/y): [lasterror, T];

["numeric exception: division by zero", "numeric exception: division by zero"]

> x:=0: if traperror(Kr*sin(x)/x) = lasterror then limit(Kr*sin(t)/t, t=x) end if; ⇒ Kr

> x:=0: if lasterror = traperror(Kr*sin(x)/x) then G:=limit(Kr*sin(t)/t, t=x) end if; G; ⇒ G

> x:=0: if lasterror=traperror(Kr*sin(x)/x) then G:=limit(Kr*sin(t)/t, t=x) end if; G;

G := Kr Kr

Последний пример фрагмента иллюстрирует тот факт, что порядок следования переменной lasterror и вызова traperror-функции в логической паре в общем случае существенен и первой следует кодировать traperror-функцию. Между тем, повторное выполнение ifпредложения последнего примера фрагмента возвращает корректные результаты, т. к. значение lasterror-переменной сохраняет последнюю ошибочную ситуацию. Ниже мы еще раз вернемся к рассмотренным средствам обработки ошибочных и особых ситуаций, однако следует отметить, что traperror-функция в значительной мере является устаревшим (obsolete) средством и его заменяет появившееся для данных целей в Maple 6 более функционально широкое try-предложение, рассматриваемое ниже.

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

По time-функции, имеющей формат кодирования следующего простого вида: time({ |<Выражение>})

возвращается соответственно общее время {от начала текущего сеанса работы с пакетом| вычисления указанного выражения} в с. в float-формате. При этом, следует иметь в виду, что использование второго формата кодирования time-функции позволяет получать время вычисления заданного ее фактическим аргументом выражения без учета времени, затраченного на его упрощение, т.е. чистое время вычисления. Первый формат time-функции используется, как правило, в виде конструкций продемонстрированного в нижеследующем фрагменте типа, тогда как второй формат более удобен для временной оценки вычисления отдельных выражений в чистом виде. Если же требуется оценить общее время вычисления сложного выражения, включая затраты на его упрощение, следует воспользоваться первым форматом time-функции. Следующий фрагмент иллюстрирует применение time-функции для временных оценок:

> t:= time( ): G:= sin(10.3^8!): t1:= time( ): printf(`%s%1.3f%s`,`Время вычисления выражения "sin(10.3^8!)" равно: `, t1 - t, ` сек.`);

Время вычисления выражения "sin(10.3^8!)" равно: 29.781 сек.

Time := ( ) → evalfmap2`*`, time( ), 601 , 36001 , 2

> Time(); ⇒ [0.014, 0.00023]

Фрагмент включает пример простой Time-процедуры, возвращающей общее время от начала текущего сеанса работы с пакетом в минутах и часах. Функция time используется для организации управления вычислениями в контексте их временных характеристик и может служить в качестве средства управления непредсказуемыми по времени вычислениями (циклы, итерации и др.).