1.6.5. ПРИМЕР: СРАВНЕНИЕ МНОЖЕСТВ
В качестве примера использования логических связок и рекурсии рассмотрим следующую задачу.
Как известно из теории множеств, два множества считаются равными, если они состоят из одних и тех же элементов. Предположим, что мы хотим запрограммировать на Рефале операцию сравнения конечных множеств на равенство. Для этого прежде всего следует придумать какой-то способ изображения множеств в виде объектных выражений. Сначала рассмотрим множества, элементами которых могут быть только символы (в смысле Рефала). Тогда множество символов
{Os1, Os2, ..., Osn} можно изобразить в виде объектного выраженияOs1 Os2 ... Osn
При этом оказывается, что одному и тому же множеству могут соответствовать несколько его изображений. Например, множество {John, Mary} можно изобразить как в виде выражения John Mary, так и в виде выражения Mary John , или даже в виде Mary John John Mary . Таким образом, неравные выражения могут изображать равные множества. Как известно, элементы множеств сами могут быть множествами. Поэтому мы теперь несколько усложним нашу задачу. Предположим, что рассматриваемые нами множества могут содержать в качестве элементов как символы, так и множества (которые, в свою очередь снова могут содержать множества и т.д.). Теперь мы должны как-то изобразить те элементы множества которые сами являются множествами. Мы поступим следующим образом. Если элемент множества - символ Os, мы будем его изображать в виде символа Os. Если же элемент множества - множество X, мы будем изображать его в виде терма вида (X'), где X' - изображение множества X. Таким образом, множество {A, {A,B}, {A}} можно изобразить, например, в виде выражения A (A B) (A) . Теперь постараемся определить функцию-предикат Eqset? , которая будет определять, являются ли два ее аргумента представлениями одного и того же множества. Для этого мы постараемся разложить понятие равенства множеств на более простые понятия.А именно, два множества
A и B равны в том и только том случае, если A является подмножеством B и B является подмножеством A. Далее, множество A является подмножеством множества B в том и только том случае, если для любого элемента X множества A верно, что X принадлежит B.Поэтому мы определим не одну, а четыре функции-предиката:
Eqset? будет проверять, что ее аргументы представляют одно и то же множество, Subset? будет проверять, что множество, представляемое первым аргументом, является подмножеством множества, представляемого вторым аргументом, El? будет проверять, что ее первый аргумент представляет элемент, входящий в множество, представляемое вторым аргументом, а Eqel? будет проверять, что ее аргументы представляют один и тот же элемент множества.Интересно отметить, что если два элемента множества сами являются множествами, то их сравнение приводит к необходимости сравнивать два множества, поэтому функция
Eqel? вынуждена вызвать функцию Eqset? . Таким образом, оказывается, что функция Eqset? в конечном итоге рекурсивно определяется через себя.$func? Eqset? (eA)(eB) = ;
$func? Subset? (eA)(eB) = ;
$func? El? tX (eA) = ;
$func? Eqel? tX tY =;
Eqset? (eA)(eB) =
<Subset? (eA)(eB)><Subset? (eB)(eA)>;
Subset? (eA)(eB) =
eA :
{
= ;
tX eR = <El? tX (eB)><Subset? (eR)(eB)>;
};
El? tX (eA) =
eA : tY eR,
\{ <Eqel? tX tY>; <El? tX (eR)>; };
Eqel? tX tY =
\{
tX tY : s s
= tX : tY;
tX tY : (eA)(eB)
= <Eqset? (eA)(eB)>;
};