В Прологе разрешено использовать встроенные отношения для конструирования других полностью определяемых пользователем отношений. Например, можно задать отношение "меньше или равно" следующим образом:
х leq х
х leq у
if x LESS у
Первая строка этого определения используется для констатации того факта, что любое число меньше или равно самому себе. Во второй строке утверждается, что х меньше или равно у, если х строго меньше у. В запросах это отношение можно использовать так:
is (2 leq 5)
is (2 leq 2)
Ответом на оба эти запроса будет YES.
Упражнение 2.6
Определите отношение "больше или равно", назвав его geq.
Упражнение 2.7
Прокомментируйте следующие запросы:
a) is (2 leq х);
б) is (x leq 2);
в) all (x: x leq 5).
Запросы, аналогичные is (2 leq 5), не имеют особого смысла, поскольку ответ известен заранее. Но следует отметить, что некоторые очень важные отношения можно определить, используя отношение leq. Предположим, необходимо сформулировать отношение in, определяющее числа, во-первых, принадлежащие заданному интервалу и, во-вторых, отстоящие друг от друга на одно и то же значение, и использовать его для генерации и проверки правильности этих чисел.
Первая предварительная попытка может выглядеть так:
х in (у z) if
у leq x
and х leq z
Здесь обозначение (у z) использовано для того, чтобы показать, что нижней границей интервала является у, а верхней - z. Интервал, в который включены как нижняя, так и верхняя границы, называется отрезком или закрытым интервалом. Открытым называется интервал, которому не принадлежат либо обе его границы, либо одна из них.
Рассмотрим запросы
is (5 in (2 9))
is (3 in (6 9))
Оба эти запроса правильны. Ответами на них являются YES и NO соответственно. Таким образом, определенное выше отношение можно использовать для проверки принадлежности заданного числа заданному интервалу. Но обработка запросов вида
all (x: х in (4 6))
приводит к ошибкам. Попробуем объяснить, почему. Объяснение надо искать в анализе последних двух заданий упражнения 2.5. Наш пример приводит к необходимости сначала выполнить операцию LESS (4 х). Но ее выполнить невозможно, поскольку значение х неизвестно.
Фактически заданному интервалу принадлежит очень много чисел: 4.0, 4.1, 4.23, 4.2345 и т.д., т.е. для того чтобы четко определить числа, включаемые в интервал, необходимо задать еще и разность между двумя любыми последовательными значениями, принадлежащими интервалу. Принимая это во внимание, попробуем записать программу так:
X In (XT) if
X(eq Y
X in(Y Z)if
SUM (У lx) and
x leq Z and
X in(x Z)
Обратите внимание на использование в этой программе больших и малых букв.
Первое правило программы гарантирует, что нижняя граница всегда будет меньше верхней, и делает нижнюю границу первым искомым числом. Второе правило представляет собой механизм генерации остальных чисел, входящих в интервал. Этот механизм обеспечивает добавление 1 к нижней границе, проверяет, меньше или равен результат верхней границе, и, наконец, устанавливает, принадлежит ли X только что определенному интервалу. Таким образом будет формироваться возрастающая последовательность чисел с шагом, равным единице.
Например, в ответ на запрос
all (x: х in (3 7))
будут получены все целые в интервале от 3 до 7.
Аналогично, в ответ на запрос
all (x: х in (2.5 5.5))
будет получена следующая последовательность чисел:
2.5, 3.5, 4.5, 5.5.
Для того чтобы установить любой нужный Вам шаг, необходимо изменить отношение SUM во втором правиле следующим образом:
SUM (Y n х)
где n - желаемое значение шага. Тогда для генерации последовательности с шагом, например, 0.5 необходимо использовать
SUM (Y 0.5 х)
Заметим, что во втором правиле отношение in определяется через самое себя. Такие определения называются рекурсивными. Рекурсия допускается в таких языках программирования высокого уровня, как Алгол и Паскаль. В этих языках использование рекурсии сводится к вызову процедурами самих себя. В Прологе использование рекурсии позволяет добиться ясности и в то же время лаконичности при конструировании правил. Рекурсия довольно удобна для задания числовых отношений, но может быть использована и в других случаях, например, для обработки списков. Но этим вопросом мы займемся позднее.
Упражнение 2.8
Используя отношение leq, определить отношение "больше чем", обозначив его gt.
Упражнение 2.9
а. Используя приведенное выше отношение in, определить, что будет напечатано в ответ на запрос
all (х: х in (0 n))
б. Сформировать запрос для получения всех целых чисел в диапазоне от 1 до 100.
в. Переписать второе правило в определении отношения in таким образом, чтобы обеспечить генерацию последовательности 0, 0,1, 0.2 и т. д.
г. Модифицировать отношение in таким образом, чтобы обеспечить получение чисел в интервале (X Y), не включая в него верхней границы Y.
д. Модифицировать определение отношения in для получения убывающей последовательности чисел.
Отношение in можно использовать по-разному. Например, с его помощью можно определить все делители заданного числа. Это может быть сделано так:
all (x у: х in (2 28) and у in (2 28) and TIMES (x у 28))
В ответ на такой запрос будет напечатано
2
4
7
14
14
7
1
2
Для того, чтобы устранить повторения" перепишем запрос иначе:
all (х у: х in (2 28) and у in (2 28) and x LESS у and TIMES (x у 28))
Можно оформить процесс получения делителей в виде отдельного отношения: