Пример. Напишем программу, реализующую компьютерный вариант телефонного справочника. Основное назначение этой не очень сложной программы — находить по фамилии человека его телефонный номер или, наоборот, по телефонному номеру — фамилию владельца телефона. У пользователя нашей программы должна быть возможность добавлять информацию в базу данных, а также удалять и изменять устаревшую информацию.
Приступим к реализации нашего проекта. Внутренняя база данных будет содержать факты, описывающие единственный предикат, имеющий два аргумента. Первым аргументом предиката будет фамилия человека, а вторым — его телефонный номер. Для упрощения программы будем считать, что соответствие между фамилиями и номерами телефонов взаимооднозначное, то есть каждой фамилии соответствует не более одного телефонного номера, и наоборот.
Сделаем так, чтобы при запуске программы появлялось меню, из которого пользователь мог выбрать, какое действие с телефонной базой он хотел бы осуществить. Реализуем пять операций:
- Получение информации о телефонном номере по фамилии человека.
- Получение информации о фамилии абонента по телефонному номеру.
- Добавление новой записи в телефонную базу.
- Изменение существующей в телефонной базе записи.
- Удаление записи из телефонной базы.
Нужно учесть, что пользователь может ошибиться и нажать клавишу, не соответствующую ни одной из пяти указанных операций. После выполнения каждой из операций программа должна вернуться обратно в меню, чтобы у пользователя не было необходимости запускать программу заново, если ему нужно выполнить еще одно действие.
Кроме того, у пользователя должна быть возможность выйти из программы, не совершая никаких действий. При выходе из программы факты телефонной базы должны быть сохранены из оперативной памяти в файл на диске, а оперативная память очищена от ненужных фактов.
Эти действия выполняет следующее правило (символ '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. /* вызываем меню */
Приведем полный текст программы.
Листинг
13.1.
Программа, реализующая компьютерный вариант телефонного справочника.
(html,
txt)