Язык запросов
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, соответственно.