159
Сделаем необходимые пояснения. Выполнение функции f
начинается с того, что вызывается функция проверки соответствия
аргумента первому уравнению f_0. Эта функция прежде всего проверит,
соответствует ли аргумент первому образцу (вызов f_0_pattern x).
Если аргумент не удовлетворяет образцу, то будет вызвана функция
второго уравнения f_1 и так далее, пока либо не будет обнаружено
соответствие, либо ни одно из уравнений не будет признано подходящим,
и в этом последнем случае будет сделано обращение к функции error,
вызывающей аварийное окончание работы программы. Далее, если
соответствие образцу обнаружено, то выполняется связывающий код, в
котором каждой из переменных образца ставится в соответствие некоторая
часть аргумента. Этот код представляет собой
часть блока let и записан в
нашем выражении в виде <f_i_bind x>. После выполнения связывания
производится еще одна проверка – проверка на соответствие аргумента
условию охраны, если, конечно, охрана имеется в уравнении (вызов
f_i_test x). Это условие проверяется в ситуации, когда уже выполнен
связывающий код, и поэтому находится внутри тела соответствующего
блока. Если
условие не выполняется, то будет продолжена проверка
уравнений, если же условие выполнено, то исполняется код,
соответствующий правой части соответствующего уравнения (вызов
f_i_right x), и на этом работа функции будет завершена.
Теперь осталось понять, как должны быть написаны все коды,
упомянутые, но не реализованные в нашем определении функции f: коды
соответствия образцу f_i_pattern
, связывающие коды f_i_bind,
коды условий f_i_test и коды правых частей f_i_right. Что касается
кодов условий и кодов правых частей, то здесь никаких особенностей в
реализации нет. Соответствующие выражения из определяющих
уравнений просто переводятся на язык расширенного лямбда-исчисления в
соответствии с правилами перевода. Наиболее интересным является
вопрос о том, как
происходит проверка соответствия образцу в кодах
f_i_pattern и как организовано связывание переменных в кодах
f_i_bind.
Прежде всего, рассмотрим структуру образца. Напомним, что
образцом может быть либо простая переменная (именованная или
безымянная), либо константа, либо вызов конструктора, аргументами
которого являются другие образцы, либо, наконец, кортеж из других
образцов. На самом деле, константы
также можно рассматривать как
вызовы конструкторов без аргументов, так что фактически мы имеем
только два вида образцов: образец-переменная и образец-вызов
конструктора, однако, все-таки обычно константы представлены иначе,
чем результаты применения функций-конструкторов, так что этот случай
тоже лучше рассматривать отдельно. Если образцом является переменная,