1.5.3. ПЕРЕХВАТ НЕУСПЕХОВ В языке Рефал Плюс имеется возможность проверить, закончилось ли вычисление некоторой тропы неуспехом и, в зависимости от этого, предпринять те или иные действия.
Отрицаниями условий называются тропы вида
# S R где S - источник, а R - хвост. Если хвост R состоит из одной запятой, его разрешается опускать, в результате чего отрицание условия принимает вид # S. С синтаксической точки зрения любое отрицание условия является хвостом. Вычисление таких хвостов производится следующим образом. Первым делом делается попытка вычислить источник S. Если в результате этого получается пустое объектное выражение, результатом всего хвоста является неуспех. Если же результатом вычисления источника S является неуспех, то вычисляется хвост R, и то, что получится, считается результатом всей конструкции.Распутьями называются тропы вида
\{ Q1; Q2; ... Qn; }
где Q1, Q2, ..., Qn - некоторые тропы. С синтаксической точки зрения любое распутье является источником. Вычисление распутья происходит следующим образом. Первым делом делается попытка вычислить тропу Q1. Если в результате этого получается объектное выражение Oe, оно считается результатом всего распутья. Если же результатом вычисления тропы Q1 является неуспех, то делается попытка вычислить \{Q2; ..., Qn;}, и то, что получится, является результатом всего распутья. Таким образом, распутье "перехватывает" неуспехи. Если результатом вычисления всех троп является неуспех, то и результатом всего распутья является неуспех.Рассмотрим, например, тропу
1 :: sX,
\{ sX : 0 = 1; sX : 1 = 0; }
Она вычисляется следующим образом. Первым делом выполняется определение локальной переменной 1 :: sX, в результате чего sX получает значение 1. После этого делается попытка вычислить первую тропу распутья, т.е. sX : 0 = 1. При попытке выполнить сопоставление sX : 0 выясняется, что сопоставление проходит неуспешно, поэтому результатом этой тропы является неуспех. Вследствие этого делается попытка вычислить следующую тропуsX : 1 = 0
, в результате чего получается результат 0, который и является результатом вычисления всей тропы. В некоторых случаях, однако, полезным оказывается другой вариант распутья, имеющий следующий вид:{ Q1; Q2; ... Qn; }
Его отличие от предыдущего варианта проявляется в том, что если результатом вычисления всех троп является неуспех, то результатом вычисления распутья является ошибка $error(Fname "Unexpected fail"), где Fname - имя функции, в которой находится распутье. Таким образом, мы можем считать, что пара скобок \{ ... } "прозрачна" для неуспехов, в то время как пара скобок { ... } для них "непрозрачна", ибо неуспех не может "выскочить" из распутья { Q1; Q2; ... Qn; }. Довольно часто встречаются тропы следующего вида:S : Ve, \{Ve : Snt1; Ve : Snt2; ..., Ve : Sntn;}
S : Ve, {Ve : Snt1; Ve : Snt2; ..., Ve : Sntn;}
где Ve - некоторая e-переменная, которая больше нигде в определении функции не используется, а каждое из предложений Sntj имеет вид Pj Rj. Для таких троп предусмотрена, соответственно, следующая сокращенная форма записи:S : \{Snt1; Snt2; ... Sntn;}
S : {Snt1; Snt2; ... Sntn;}
называемая выбором, при этом конструкции \{Snt1; Snt2; ... Sntn;} и {Snt1; Snt2; ... Sntn;} называются образцовыми распутьями. Хвосты Rj, состоящие из одной запятой, разрешается опускать, в результате чего соответствующие предложения Pj Rj принимают вид Pj. Так, например, распутье{ sX : 0 = 1; sX : 1 = 0; }
более кратко записывается в виде выбораsX : { 0 = 1; 1 = 0; }
, а распутье\{ sX : A,; sX : B,; }
может быть сокращено доsX : \{ A; B; }
С синтаксической точки зрения, все выборы являются источниками, что позволяет записывать, например, присваивания следующего вида:sX : { 0 = 1; 1 = 0; } :: sY = <"+" sX sY>
При этом сначала вычисляется источникsX : {0 = 1; 1 = 0;}
, затем полученный результат присваивается переменной sY, после чего вычисляется тропа= <"+" sX sY>.