Читаем Программирование на языке Пролог полностью

Последние несколько утверждений этой программы определяют предикат целое_имя, который используется для преобразования целого числа в последовательность литер-цифр. Атомы, порождаемые генатом, формируются с помощью встроенного предиката name, который формирует атом из литер корня, за которыми следуют цифры номера. В некоторых реализациях Пролога используется версия предиката name, которая выполняет также функции предиката целое_имя, однако весьма поучительно посмотреть, как его можно определить на Прологе. В этом определении неявно используется тот факт, что коды ASCII для цифр 0, 1, 2 и т. д. равны соответственно 48, 49, 50 и т. д. Поэтому, чтобы преобразовать число меньшее 10 в код ASCII соответствующей цифры, достаточно прибавить к этому числу 48. Перевести в последовательность литер число, большее 9, сложнее. Последнюю цифру такого числа получить легко, поскольку это просто остаток от деления на 10 (число mod 10). Таким образом, цифры числа легче формировать в обратном порядке. Мы просто циклически повторяем следующие операции: получение последней цифры, вычисление остальной части числа (результат его целого деления на 10). Определение этого на Прологе выглядит следующим образом:

цифры_наоборот(N,[С]):- N‹10,!, С is N+48.

цифры_наоборот(М,[С|Сs]):-С is (N mod 10) + 48,N1 is N/10,цифры_нaoбopот(N1,Cs).

Чтобы получить цифры в правильном порядке, применим трюк: в этот предикат добавим дополнительный аргумент – список «уже сформированных» цифр, С помощью этого аргумента мы можем получать цифры по одной в обратном порядке, но в итоговый список вставлять их в прямом порядке. Это делается следующим образом. Пусть у нас есть число 123. В начале список «уже сформированных» цифр есть []. Первым получаем число 3, которое преобразуется в литеру с кодом 51. Затем мы рекурсивно вызываем целое_имя, чтобы найти цифры числа 12. Список «уже сформированных» цифр, который передается в это целевое утверждение, содержит литеру, вставленную в исходный список «уже сформированных» цифр – это список [51]. Вторая цель целое_имя выдает код 50 (для цифры 2) и снова вызывает целое_имя, на этот раз с числом 1 и со списком «уже сформированных» цифр [50, 51]. Эта последняя цель успешно выполняется и, поскольку число было меньше 10, дает ответ [49,50,51]. Этот ответ передается через аргументы разных целей целое_имя и дает ответ на исходный вопрос – какие цифры соответствуют числу 123?

Приведем теперь всю программу полностью.

/* Породить новый атом, начинающийся с заданного корня, и оканчивающийся уникальным числом. */

генатом (Корень,Атом),выдать_номер(Корень,Номер), name(Корень,Имя1), целое_имя(Номер,Имя2), присоединить(Имя1,Имя2,Имя), name(Атом,Имя).

выдать_номер(Корень, Номер):-retract(тeк_номер(Корень, Номер1)),!,Номер is Номер 1 + 1, asserta(тек_номер(Корень, Номер)).

выдать_номер(Корень,1):- asserta(тек_номep(Kopeнь,l)).

/* Преобразовать целое в список цифр */

целое_имя(Цел,Итогспи):- целое_имя (Цел, [], Итогспи).

целое_имя(I,Текспи,[С|Текспи]:- I ‹10,!, С is I+48.

целое_имя(I,Текспи,Итогспи):-Частное is I/10, Остаток is I mod 10,С is Остаток+48.

целое_имя(Частное,[С|Текспи],Итогспи).

Генератор списков структур (найтивсе)

В некоторых прикладных задачах полезно уметь определять все термы, которые делают истинным заданный предикат. Например, мы могли бы захотеть построить список всех детей Адама и Евы с помощью предиката родители из гл. 1 (и располагая базой данных с фактами родители о родительских отношениях). Для этого мы могли бы использовать предикат по имени найтивсе, который мы определим ниже. Цель найтивсе(Х,G, L) строит список L, состоящий из всех объектов X таких, что они позволяют доказать согласованность цели G. При этом предполагается, что переменная G конкретизирована произвольным термом, однако таким, что найтивсе рассматривает его как целевое утверждение Пролога. Кроме того переменная X должна появиться где-то внутри G. Таким образом G может быть конкретизирована целевым утверждением Пролога произвольной сложности. Для того, чтобы найти всех детей Адама и Евы, необходимо было бы задать следующий вопрос:

?- найтивсе(Х, родители(Х,ева,адам), L).

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже