В.Н. Пильщиков - Язык Плэнер (1156455), страница 27
Текст из файла (страница 27)
Из числа ранее рассмотренных встРоенных функций к ним относятся функции ВЕР1ХЕ, Р1ДБТ, ВЕАВ, РВ1ХТ, МРВ1ХТ, ОРЕХ, ОСОБЕ, АСТ!УЕ и В161ТБ. Таким образом, при возвратах по неуспеху не отменяется: пи определение новой процедуры, ни полная смена списка свойств идентификатора, ни ранее сделанный ввод или вывод, ни открытие или закрытие файла, ни объявление его активным файлом, ни ранее установленное количество печатаемых цифр в дробной части вещественных чисел.
В то же время при вычислении встроенных функций ЯЕТ, АВО1, ЯУВ1, Р1Х, 11ХАББ10Х, ЕСОР, РОВ, РОТ, СЕЕТ и 1Я обратные операторы запоминаются всегда, поэтому при неуспехе произведенные этими функциями иаменения ликвидируются: обратные операторы функций БЕТ, АВВ1, БУВ1, Г1Х и ОХАББ10Х, изменяющих и уничтожающих значения переменных, восстанавливают при неуспехе прежние значения переменных; при выполнении функцнй ЕСОР и РОВ обратные операторы запоминаются всякий раз, когда параметру цикла присваивается новое аначенпе, поэтому при воаврате по неуспеху на какой-то из предыдущих шагов цикла,у параметра всегда восстанавливается значение, соответствующее именно этому шагу цикла; обратный оператор функции РОТ, которая изменяет аначение одного иэ свойств некоторого идентификатора, восстанавливает при неуспехе прежнее значение этого свойства; обратный оператор функции СЯЕТ либо,восстанавлнвает прежнее эначение константы, измененное этой функцией, либо уничтожает константу, если она была введена в программу именно этой функцией СВЕТ (однако обратный оператор не восстанавливает ту процадуру, которая, воэможно, была уничтожена при определении константы); при вычислении функции 1Я, т.
е. при сопоставлении образца с .'выражением, обратные операторы эапоминаются всякий раэ, когда изменяется аначение какой-нибудь переменной образца, поэтому при распространении неуспеха все присваивания'переменным обрааца будут отменены (см. также $3.9). Таким образом, любое иэменение в значениях переменных, констант или свойств идентификаторов отменнется при неуспехе. Это не всегда выгодно, поэтому для некоторых иэ перечисленных функций введены «двойники» вЂ” функции с аналогичными действиями, но при вычислении которых обратные операторы не эапоминаются и, эначит, побочнын эффект которых не уничтожается при неуспехе. Наэвания функций-двойников обраэуются добавлением буквы Р (от слова регшапепь — постоянный) к именам исходных функций: [РЯЕТ 1 е], БПВК [РАВШ 1], ЯПВК [РБСВ1 1], ЯСВК [РР11) й В], БПВК [РР()Т $ 1вд и], ЯПВК [РСБЕТ 1 е], Б()ВК (У функций ()МАЯЯ1СИ, 1.00Р, РОВ и 18 двойников нет.) Функции-двойники применяются в тех случаях, когда вараиее иэвестно, что выполняемое действие не должно отменяться при неуспехе, или когда беэраэлично, будет отменяться действие или нет, и потому ради экономии памяти лучше испольэовать, скажем, функцию РЯЕТ, а не фушгцию ЯЕТ.
Рассмотрим типичный' пример иснольэовання функции РЕЕТ: [РКОО (Х (Т ())) [А1.Т () [КЕТПКН Х~] [РБЕТ Х [ФЯ]] [РЯЕТ Т (!.У .Х)] [РАН]] При вычислении етого выражения создается список У всех решений задачи о восьми ферзях. Если бы не было функцииРЯЕТ, сделать ато не удалось бы. В самом деле, если вместо оператора [РЯЕТ г (! г" .Х)] ааписать оператор [ЯЕТ У (!."г' .Х)], то при каждом неуспехе уничтожалаеь бы.только что сделанная вались 129 9 н. ы. пвльщиэев очередного решения Х в список Т, поэтому у переменной Т всегда сохранялось бы начальное значение (). Применение же функции РБЕТ «спасает» список Т от таких ненужных восста-.
новлений. Что же касается переменной Х, то совершенно безразлично, будет или нет восстанавливаться при неуспехе ее прежнее значение, поэтому, чтобы не запоминать лишний обратный оператор, мы и написали оператор [РЯЕТ Х [Ф8)] вместо также допустимого оператора [ЯЕТ Х [Ф8)]. Следует отметить, что функция РБЕТ (и ей подобные функции) не запоминает обратный оператор только для себя и не оказывает никакого влияния на другие присваивания. Поэтому виачением выражения [РВ00 ((ХА)) [А1Т () [ВЕТПВ)«) .Х]] [ЯЕТ Х В] [РБЕТ Х С] [РА)Ь] ] является атом А, но не атом С, как может показаться. Действительно, при вычислении [БЕТ Х В] переменной Х присваивается значение В и .одновременно запоминается обратный оператор [ЯЕТ Х А]. Затем аначенне переменной Х меняется с В 'на С, и при атом обратный оператор не запоминается. Но это не овна« чает, что переменная Х сохранит значение С. Указанный обратный оператор остался, он-то при неуспехе и восстановит у Х значение А.«Таким образом, если мы хотим, чтобы некоторая переменная не изменяла при неуспехе своего значения, то следует все присваивания ой производить только функцией РЯЕТ, а не вперемежку с функцией ЯЕТ.
Рассмотрим еще один пример: [ПЕР1ИЕ 1ЕРП«)1ТЕ [ЬАМВПА .() [РВ00 ((Х О)) А [А1Т [РАПП1 Е] [00 А]]]Ц Эта функция подобна развилке с бесконечным числом альтернатив, каждая из которых — очередное натуральное число."Дей ствительно, при возврате к втой функции по неуспеху Р-точка функции АЬТ уничтожается, но.затем вновь выаывается функция А1,Т, т. е.
тут же ставится новая Р-точка. Получается как бы иеуничтожаемая Р-точим Кроме того, функция РАПП1 не запоминает обратный оператор, поэтому присваиваемое ею значение переменной )«) сохраняется и после возврата по неуспеху. Тем самым каищый рав вначение переменной И увеличивается на 1, что и обеспечивает выдачу всех натуральных чисел. 130 3.6. Уничтожение развплок и обратных операторов Теперь мы рассмотрим встроенные функции яаыка, с помощью которых можно уничтожать ранее' запомненные обратные операторы и Р-точки.
Если заранее известно, что после вычисления какого-то выражения должны быть уничто»коны Р-точки и/или обратные операторы, которые появились во время вычисления этого выражения (для краткости будем говоритьс «внутри этого выражения»), то применяется одна иа функций РЕЕМ, ЯТКО или ТЕМР.
Функцвш РЕЕМ: [РЕЕМ «], РБ()ВК Эта функция вычисляет свой аргумент е. Если его вычисление неуспешно, то неуспешным является и вычисление функции. Иначе функция успешно аакацчивает свою работу со значением З, но перед выходом она уничтожает все Р-точки и 'обратные операторы внутри е.
Например, в реаультате вычисления выражения [РКОО ((Х А)) [А1Т () [КЕТ()К(«) .Х]] [РЕКМ [АЬТ [ЯЕТ Х В] [РК1г)Т С]]] [РА1Ц ] будет получено значение В, причем печататься ничего не будет. Действительно, функция РЕЕМ уничтоя«ает как развилку функции АЬТ, так и обратный оператор 'функции ЯЕТ, поэтому неуспех, выработанный функцией РА1Ь, не восстанавливает прежнее значение А переменной Х и будет «пойман» только Р-точкой первой функции А1.Т.
Функция РЕЕМ применяется тогда, когда вычисление некоторого выражения не должно возобновляться при неуспехе и когда все, что сделано при вычислении атого выражения, не должно быть отменено при неуспехе. Функция используется и в тех случаях, когда надо спасти 'память, которую транслятор яаыка тратит .на запоминание обратных операторов и Р-точек. Например, если в задаче о восьми ферзях нас интересует только первое решение, то следует вычислять выражение [РЕКМ [ФЗ]], чтобы после успешного вычисления функции ФЗ внутри пее не оставалось ни Р-точек, ни обратных операторов, которые уже не нужны.
Отметим, что вычисление выражения [РЗЕТ Х е] во многом похоже на вычисление выражения [РЕЕМ [ЯЕТ Х е]], но если в первом случае обратный оператор просто не запоминается, то во втором случае функция ЗЕТ запоминает его, а затем функция РЕЕМ уничтожает его.
Однако есть и более важное различие между этими выражениями: функция РЯЕТ не уничтожает Р-точ- 9« 131 ки и обратные операторы внутри своего аргумента е, в то время как функция РЕЕМ заодно с обратным оператором функции ЯЕТ уничтонсает и все Р-точки и обратные операторы внутри «. Поэтому вычисление выражения [110 [РЯЕТ Х [А1 Т А [ЕХ1Т .Х 1)О]]] [РА1Ц] успешно и выдает аначение А, в то время как вычисление вырал«ения [ОО [РЕКМ [ЯЕТ Х [А1 Т А [ЕХ1Т .Х 1)О]]]] [РА1Е] ] неуспешно. Может случиться так, что прк вычислении аргумента функции РЕКМ произошел «насильственный» выход из нее (с помощью функции 60, КЕТОВА или ЕХ1Т). Тогда функция РЕЕМ не выполняет свои «выходные» действия.
Например, после вычисления [РЕКМ [ВО [ЯЕТ Х [АМОКО .1]] [ЕХ1Т () РЕЕМ]]] сохраняются как Р-точка функции АМО1(6, так и обратный оператор функии ЯЕТ. Данное замечание справедливо и для функций ЗТВ6 и ТЕМР. Функция ЗТВ6: [ЯТВ6 е], ГЯ()ВВ.. Эта функция действует аналогично функции РЕКМ, но уничтожает только Р-точки внутри своего аргумента е, сохраняя обратные операторы. Найример, в результате вычисления выражения [РВО6 ((Х А)) [А(Т () [ВЕТ()ВР(.Х]] [ЗТОК [АХ,Т [РВ1НТ [ЯЕТ Х ВЦ [РК11)Т 6]]] [РАН ]] будет получено аначение А и будет напечатано тольио В.
Функция ЗТВ6 применяется в тех случаях, когда неуспех не должен возобновлять вычисление выражения е, но должен уничтожить все побочные аффекты первого вычисления етого выражения. Функция ТЕМР» [ТЕМР е], РЯУВВ, Эта функция вычисляет свой аргумент е. Если зто вычисление неуспешно, то неуспешно и вычисление функции. Иначе функция успешно заканчивает свою работу со аначением Е', а перед выходам выполняет следующие действия: уничтожает все Р-точки 132 внутри и и выполняет все обратные операторы, которые были аапомнены при вычислении е. Таким образом, функция ТЕМР сама уничтожает побочные эффекты, имевшие место при вычислении ее аргумента. Например, в реэультате вычисления выражения [РВ06 ((Х А)) [ТЕМР [А1 Т [РК1НТ [ЯЕТ Х В]] [РК!НТ С]]] .Х] будет получено эначение А и будет напечатано только В.