|
После приведения формулы вида ПНФ к виду ССФ вы получаете формулу, в безквантовой матрице которой дизъюнкт содержит оба контранрных атома: |
Внутренние (динамические) базы данных
Пример. Напишем программу, реализующую компьютерный вариант телефонного справочника. Основное назначение этой не очень сложной программы — находить по фамилии человека его телефонный номер или, наоборот, по телефонному номеру — фамилию владельца телефона. У пользователя нашей программы должна быть возможность добавлять информацию в базу данных, а также удалять и изменять устаревшую информацию.
Приступим к реализации нашего проекта. Внутренняя база данных будет содержать факты, описывающие единственный предикат, имеющий два аргумента. Первым аргументом предиката будет фамилия человека, а вторым — его телефонный номер. Для упрощения программы будем считать, что соответствие между фамилиями и номерами телефонов взаимооднозначное, то есть каждой фамилии соответствует не более одного телефонного номера, и наоборот.
Сделаем так, чтобы при запуске программы появлялось меню, из которого пользователь мог выбрать, какое действие с телефонной базой он хотел бы осуществить. Реализуем пять операций:
- Получение информации о телефонном номере по фамилии человека.
- Получение информации о фамилии абонента по телефонному номеру.
- Добавление новой записи в телефонную базу.
- Изменение существующей в телефонной базе записи.
- Удаление записи из телефонной базы.
Нужно учесть, что пользователь может ошибиться и нажать клавишу, не соответствующую ни одной из пяти указанных операций. После выполнения каждой из операций программа должна вернуться обратно в меню, чтобы у пользователя не было необходимости запускать программу заново, если ему нужно выполнить еще одно действие.
Кроме того, у пользователя должна быть возможность выйти из программы, не совершая никаких действий. При выходе из программы факты телефонной базы должны быть сохранены из оперативной памяти в файл на диске, а оперативная память очищена от ненужных фактов.
Эти действия выполняет следующее правило (символ '0' означает, что пользователь нажал соответствующую клавишу):
m('0'):–
save("phones.ddb "), /* сохраняем телефонную базу
в файл */
retractall(_)./* удаляем все факты из внутренней
базы данных */В начале работы программы факты из телефонной базы, хранящейся в файле на диске, должны загружаться во внутреннюю базу данных, в случае, если такой файл существует.
Предикат, предназначенный для выполнения этих действий, выглядит следующим образом:
start:–
existfile("phones.ddb"),!,
/* если существует файл с телефонной базой */
consult("phones.ddb "),
/* , то загружаем факты во внутреннюю базу
данных */
menu. /* и вызываем меню */
start:–
menu. /* если такого файла еще нет, просто
вызываем меню */Если пользователь выбрал первую операцию, должен быть выдан телефонный номер абонента (если в телефонной базе имеется соответствующий факт) или сообщение о том, что в телефонной базе нет такой информации.
Это реализуют два приведенных ниже предиката.
m('1'):–
write("Введите фамилию"), nl,
/* выводим приглашение ввести фамилию */
readln(Name), /* читаем введенную фамилию
в переменную Name */
name_phone(Name, Phone),
/* вызываем предикат, который
помещает в переменную Phone
телефонный номер, соответствующий
фамилии Name или сообщение
об отсутствии информации */
write("Номер телефона: ",Phone),
/* выводим значение переменной
Phone */
readchar(_), /* ждем нажатия любой клавиши */
menu. /* возвращаемся в меню */
name_phone(Name,Phone):–
phone(Name,Phone),!.
name_phone(_,"Нет информации о телефонном номере").
/* если нужного факта во внутренней
базе данных не нашлось,
то вместо телефонного номера
возвращаем соответствующее
сообщение */Если пользователь желает выполнить вторую операцию, то должна быть выведена фамилия абонента, если в нашей телефонной базе имеется соответствующий факт. Иначе выводится сообщение о том, что у нас нет такой информации.
Соответствующие предикаты будут выглядеть следующим образом:
m('2'):–
write("Введите номер телефона"),nl,
readln(Phone),
phone_name(Name, Phone),
write("Фамилия абонента: ",Name),
readchar(_),
menu. /* вызываем меню */
phone_name(Name,Phone):–
phone(Name,Phone).
phone_name("Нет информации о владельце телефона",_).
/* если нужного факта во внутренней базе
данных не нашлось, то вместо фамилии
абонента возвращаем соответствующее
сообщение */Если пользователем была выбрана третья операция, то нужно дать ему возможность ввести фамилию и номер абонента, после чего добавить соответствующий факт в базу данных.
Это будет выглядеть следующим образом:
m('3'):–
write("Введите фамилию"),nl,
readln(Name),
write("Введите номер телефона"),nl,
readln(Phone),
assert(phone(Name,Phone)),
/* добавляем факт во внутреннюю
базу данных */
menu. /* вызываем меню */Если пользователь желает выполнить четвертую операцию, то нужно дать ему возможность ввести фамилию абонента и его новый телефонный номер, после чего удалить устаревшую информацию из телефонной базы (с помощью предиката retract ) и добавить туда новую информацию (используя встроенный предикат assert ).
Соответствующее этим рассуждениям предложение:
m('4'):–
clearwindow,
write("Введите фамилию"),nl,
readln(Name),
write("Введите новый номер телефона"),nl,
readln(Phone),
retract(phone(Name,_)),
/* удаляем устаревшую информацию
из внутренней базы данных */
assert(phone(Name,Phone)),
/* добавляем новую информацию
в телефонную базу */
menu. /* вызываем меню */Если пользователем была выбрана пятая операция, то нужно узнать у него, например, номер (или фамилию) абонента, после чего удалить соответствующую информацию из внутренней базы данных, воспользовавшись предикатом retract.
Запишем это предложение:
m('5'):–
write("Укажите номер телефона, запись о котором
нужно удалить из телефонной базы"), nl,
readln(Phone),
retract(phone(_,Phone)),
/* удаляем соответствующий факт
из внутренней базы данных */
menu. /* вызываем меню */Приведем полный текст программы.
DOMAINS /* раздел описания доменов */
name, number = String /* фамилию абонента и телефонный
номер будем хранить в виде
строк */
file=f /* файловый домен будем использовать для
считывания с диска и записи на диск нашей
телефонной базы */
DATABASE /* раздел описания предикатов внутренней
базы данных */
phone(name, number)
PREDICATES /* раздел описания предикатов */
name_phone(name, number) /* этот предикат находит номер
телефона по фамилии абонента */
phone_name(name, number) /* этот предикат находит фамилию
абонента по номеру телефона */
m(char) /* этот предикат реализует выполнение
соответствующего пункта меню */
menu /* этот предикат реализует вывод меню и
обработку выбора пользователя */
start /* этот предикат проверяет наличие файла
с телефонной базой на диске и либо загружает
факты из нее во внутреннюю базу данных,
если такой файл существует, либо создает
этот файл, если его не было */
CLAUSES /* раздел описания предложений */
name_phone(Name,Phone):–
phone(Name,Phone),!.
name_phone(_,"Нет информации о телефонном номере").
/* если соответствующего факта
во внутренней базе данных не нашлось,
вместо телефонного номера возвращаем
соответствующее сообщение */
phone_name(Name,Phone):–
phone(Name,Phone).
phone_name("Нет информации о владельце телефона",_).
/* если соответствующего факта
во внутренней базе данных не нашлось,
вместо фамилии абонента возвращаем
соответствующее сообщение */
menu:–
clearwindow, /* очистка текущего окна */
write("1– Получение телефонного номера
по фамилии "),nl,
write("2 — Получение фамилии абонента по номеру
телефона "),nl,
write("3 — Добавление новой записи в телефонную
базу."),nl,
write("4 — Изменение номера абонента"),nl,
write("5 — Удаление записи из телефонной базы"),nl,
write("0 — Выйти"),nl,
readchar(C), /* читаем символ с клавиатуры */
m(C). /* вызываем выполнение соответствующего пункта
меню */
m('1'):–
clearwindow,
write("Введите фамилию"), nl,
readln(Name),
name_phone(Name, Phone),
write("Номер телефона: ",Phone),
readchar(_),
menu.
m('2'):–
clearwindow,
write("Введите номер телефона"),nl,
readln(Phone),
phone_name(Name, Phone),
write("Фамилия абонента: ",Name),
readchar(_),
menu.
m('3'):–
clearwindow,
write("Введите фамилию"),nl,
readln(Name),
write("Введите номер телефона"),nl,
readln(Phone),
assert(phone(Name,Phone)),
/* добавляем факт во внутреннюю
базу данных */
menu.
m('4'):–
clearwindow,
write("Введите фамилию"),nl,
readln(Name),
write("Введите новый номер телефона"),nl,
readln(Phone),
retract(phone(Name,_)),
/* удаляем устаревшую информацию
из внутренней базы данных */
assert(phone(Name,Phone)),
/* добавляем новую информацию
в телефонную базу */
menu.
m('5'):–
clearwindow,
write("Укажите номер телефона, запись о котором
нужно удалить из телефонной базы"), nl,
readln(Phone),
retract(phone(_,Phone)), /* удаляем соответствующий
факт из внутренней базы
данных */
menu.
m('0'):–
save("phones.ddb "), /* сохраняем телефонную базу
в файл */
retractall(_)./* удаляем все факты из внутренней
базы данных */
m(_):–
menu. /* если пользователь по ошибке нажал клавишу,
отличную от тех, реакция на которые
предусмотрена, ничего плохого
не произойдет, будет отображено меню
еще раз */
start:–
existfile("phones.ddb"),!, /* если файл с телефонной
базой существует */
consult("phones.ddb "), /* загружаем факты во
внутреннюю базу данных */
menu. /* вызываем меню */
start:–
openwrite(f,"phones.ddb"),
/* если файла с телефонной
базой не существует, создаем
его */
closefile(f),
menu. /* вызываем меню */
GOAL /* раздел внутренней цели*/
Start
Листинг
13.1.
Программа, реализующая компьютерный вариант телефонного справочника.
. Как тогда проводить его унификацию, если в случае замены x на f(x) весь дизъюнкт обратится в единицу?