Язык запросов
12.3. Диалог с пользователем
В настоящем параграфе рассматривается реализация общения пользователя с компьютером.
Создается модуль mainDialog для реализации диалога с базой данных. Во время диалога пользователь может просмотреть базу данных, отредактировать базу данных (добавить или удалить факты) и просмотреть основные родственные отношения. Например, отношение "родитель – ребенок" имеет вид:
Мария Иванова - Анна Петрова Иван Петров - Анна Петрова
Кроме этого, пользователь может посмотреть на дерево предков и на дерево потомков человека, а также задать запрос к базе данных на языке, приближенном к естественному языку. Запросы должны удовлетворять определенной грамматике. Для организации диалога используется repeat-цикл. Выход из цикла выполняется по желанию пользователя о выходе из программы. Перед выходом программа спрашивает, сохранить ли изменения в базе данных. Если пользователь не дает положительный ответ, то изменения не сохраняются.
В декларацию класса mainDialog (листинг 12.8) следует поместить объявление предиката, который вызывается в разделе goal (файл mainDialog.cl).
predicates
run: ().
Пример
12.8.
Декларация класса mainDialog
Раздел goal проекта должен быть изменен следующим образом (файл main.pro):
goal
mainExe::run(main::run),
mainDialog::run().
Имплементация класса mainDialog приведена ниже (файл mainDialog.pro). Указатели на объекты классов dbrel, relation, printData и readData (они описываются ниже) хранятся в фактах-переменных. При инициализации им присваивается "значение" erroneous, что по-существу, означает, что значение им присвоено не было. Это "значение" можно присваивать динамически, кроме этого, имеется предикат проверки isErroneous(имя_факта), что часто оказывается полезным в GUI-приложениях.
open core, console
class facts
db : dbrel := erroneous.
rel : relation := erroneous.
pd : printData := erroneous.
rd : readData := erroneous.
class predicates
maindialog: ().
clauses
maindialog():-
std::repeat(),
write("\nВыберите действие:\n"
"\t1. Просмотр базы данных\n"
"\t2. Редактирование базы данных\n"
"\t3. Базовые отношения\n"
"\t4. Дерево предков\n"
"\t5. Дерево потомков\n"
"\t6. Запрос на естественном языке\n"
"\t7. Выход\n"),
X = rd:readStr(),
act(X),
!.
maindialog().
class predicates
act: (string) determ.
clauses
act("1"):- !,
write("Все записи:\n"),
pd:printDb(),
fail.
act("2"):- !,
write("Редактирование базы данных:\n"
"2.1 Добавление факта\n"
"2.2 Удаление факта\n"),
X = rd:readStr(),
act(X).
act("2.1"):- !,
write("Добавление новых сведений\n"),
Add = addData::new(rd),
Add:addNewPerson(),
fail.
act("2.2"):- !,
write("Удаление сведений:\n"),
Del = delData::new(rd),
Del:delPerson(),
fail.
act("3"):- !,
write("\nВыберите отношение: \n"
"\t3.1 Родитель\n"
"\t3.2 Отец\n"
"\t3.3 Мать\n"
"\t3.4 Муж\n"
"\t3.5 Сын\n"
"\t3.6 Дочь\n"
"\t3.7 Сестра\n"
"\t3.8 Брат\n"
"\t3.9 Предок\n"),
X = rd:readStr(),
act(X),
!.
act("3.1"):- !,
write("Отношение \"родитель - ребенок\":\n"),
rel:parent(Id1, Id2),
pd:printRel(Id1, Id2),
fail.
act("3.2"):- !,
write("Отношение \"отец - ребенок\":\n"),
rel:father(Id1, Id2),
pd:printRel(Id1, Id2),
fail.
act("3.3"):- !,
write("Отношение \"мать - ребенок\":\n"),
rel:mother(Id1, Id2),
pd:printRel(Id1, Id2),
fail.
act("3.4"):- !,
write("Отношение \"муж - жена\":\n"),
rel:husband(Id1, Id2),
pd:printRel(Id1, Id2),
fail.
act("3.5"):- !,
write("Отношение \"сын - родитель\":\n"),
rel:son(Id1, Id2),
pd:printRel(Id1, Id2),
fail.
act("3.6"):- !,
write("Отношение \"дочь - родитель\":\n"),
rel:daughter(Id1, Id2),
pd:printRel(Id1, Id2),
fail.
act("3.7"):- !,
write("Отношение \"сестра – брат или сестра\":\n"),
rel:sister(Id1, Id2),
pd:printRel(Id1, Id2),
fail.
act("3.8"):- !,
write("Отношение \"брат – брат или сестра\":\n"),
rel:brother(Id1, Id2),
pd:printRel(Id1, Id2),
fail.
act("3.9"):- !,
write("Отношение \"предок - потомок\":\n"),
rel:ancestor(Id1, Id2),
pd:printRel(Id1, Id2),
fail.
act("4"):- !,
write("Дерево предков:\n"),
T = trees::new(rd),
T:findAncTree(),
fail.
act("5"):- !,
write("Дерево потомков:\n"),
T = trees::new(rd),
T:findDescTree(),
fail.
act("6"):- !,
Q = query::new(rd, rel),
Q:query(),
fail.
act("7"):- !,
write("Выход. "),
saveDb().
act(_):-
write("\nТакого действия нет.\n"),
fail.
% Сохранение базы данных
class predicates
saveDb: ().
clauses
saveDb():-
write("Сохранить изменения в базе данных (да/нет)? "),
X = string::toLowerCase(rd:readStr()),
'д' = string::frontChar(X),
!,
db:save().
saveDb().
run():-
db := dbrel::new("family.txt"),
db:load(),
pd := printData::new(db),
rd := readData::new(pd),
rel := relation::new(db),
mainDialog(),
_ = readLine().
Пример
12.9.
Имплементация класса mainDialog
Предикат frontChar возвращает первый символ строки.
Факты-переменные db, rel, pd и rd хранят указатели на объекты классов dbrel, relation, printData и readData, соответственно.