Динамическая База данных на Turbo Prolog

от автора

Теория

Обычно программа на Прологе состоит из четырех основных программных разделов. К ним относятся:

  • раздел clauses (предложений);

  • раздел predicates (предикатов);

  • раздел domains (доменов);

  • раздел goal (целей).

Раздел clauses — это сердце Пролог-программы; именно в этот раздел записываются факты и правила, которыми будет оперировать Пролог, пытаясь разрешить цель программы.

Раздел predicates — это раздел, в котором объявляются предикаты и домены (типы) их аргументов.

Раздел domains служит для объявления всех используемых нами доменов, не являющихся стандартными доменами Пролога.

Раздел goal — это раздел, в который вы помещаете цель Пролог-программы.

Базы данных

Предикаты БД в Turbo Prolog описываются в разделе database, который должен располагаться перед разделом predicates. Все утверждения с предикатами, описанными в database, составляют динамическую БД.

БД называется динамической, так как во время работы программы у нее (БД) можно удалять любые содержащиеся в ней утверждения, а также добавлять новые. Динамическая БД (ДБД) может быть записана на диск и считана с него в оперативную память. В ДБД содержатся только факты, но не правила. В статической базе данных утверждения представлены фактами и являются частью кода программы.

Встроенные предикаты для работы с БД

Для добавления в базу данных используются следующие предикаты:

  • asserta(fact) // добавление в начало базы данных dbasedom

  • asserta(fact, dbaseName) // добавление в начало базы данных dbaseName

  • assertz(fact) // добавление в конец базы данных dbasedom

  • assertz(fact, dbaseName) // добавление в конец базы данных dbaseName

Загрузка фактов из файла:

  • consult(fileName) // загрузка в базу данных dbasedom

  • consult(fileName, dbaseName) // загрузка в базу данных dbaseName

Удаление факта:

  • retract(fact) // удаление из базы данных dbasedom

  • retract(fact, dbaseName) // удаление из базы данных dbaseName

Сохранение базы данных в файле:

  • save(fileName) // сохранение базы данных dbasedom в файле fileName

  • save(fileName, dbaseName) // сохранение базы данных dbaseName в файле fileName

Описание программы

База данных будет содержать одну таблицу — таблицу футболок, столбцы которой перечислены далее:

  1. Name — название.

  2. Price (RUB) — цена в рублях.

  3. Sex — мужская или женская футболка.

  4. Size (International) — международный размер футболки.

  5. Size (Europe) — европейский размер футболки.

  6. Color — цвет.

  7. Material — материал футболки.

  8. Production year — год производства.

Предполагаются следующие возможности программы:

  1. Считывание базы данных из CSV-файла

  2. Добавление новой записи в базу данных;

  3. Удаление футболки по названию;

  4. Изменение записи в базе данных;

  5. Поиск футболки по названию;

  6. Отображение всех футболок в консоли;

  7. Сохранение базы данных в CSV-файл;

  8. Удаление всех записей из базы данных;

  9. Выход из программы;

Код

В самом начале идёт описание всех используемых в программе доменов, баз данных и предикатов:

Domains      name, world, color, sex, material = string % домены строкового типа      europe, year, price = integer % домены целочисленного типа  file = datafile % домен типа file  arr = string* % массив из строк  integers = integer* % массив из целых чисел Database      dt_shirt(name, price, sex, world, europe, color, material, year) % описание предиката БД Predicates      repeat % зацикливает кусок кода      do_mbase % создаёт главное окно программы и вызывает предикат menu      menu % создаёт меню программы      process(integer) % ждет ввода номера функции из меню и затем вызывает её      clear_database % очищение базы данных      error % сообщает об ошибке  read_until_not_integer(integer) % ждет ввода целого числа  write_all % вывод всех футболок в командную строку  write_all(arr,integers,arr,arr,integers,arr,arr,integers) % вывод всех футболок в командную строку  write_all_csv % запись всех футболок в csv файл  write_all_csv(arr,integers,arr,arr,integers,arr,arr,integers) % запись всех футболок в csv файл  read_rows() % считывает строки из csv файла  front_string(string, string, string) % считывание одного значения из csv до разделителя ;  read_prov(integer) % ввод номера функции из меню  find(integer) % вызов предиката поиска в зависимости от введенного числа  find_shirt_name(string) % поиск футболки по имени  find_material(string) % поиск футболки по материалу  find_name(string)   find_mat(string) 

Чуть ниже находится раздел Goal, в котором содержатся предикаты, вызывающиеся при запуске программы:

Goal      do_mbase. % вызов предиката do_mbase

Ну и наконец Clauses. Здесь я опишу все правила программы.

repeat — необходимо для зацикливания. Реализуется вызовом самого себя:

repeat. repeat:-repeat.

read_prov — при вводе целого числа возвращает это число, иначе вызывает предикат error:

read_prov(Vibor):-                  readint(Vibor);                  error,                 Vibor = 0,                 menu.

Меню

Меню приложения
Меню приложения

do_mbase — предикат, с которого начинается выполнение программы. Создаёт главное окно и вызывает menu.

menu — создаёт меню и ждет пока пользователь введет число от 1 до 9. При вводе числа вызывается предикат process, который выполняет одну из девяти выбранных функций:

do_mbase :-           makewindow(1,11,3," T-SHIRTS DATABASE ",0,0,25,80),           menu,           clear_database.   menu :-           repeat, clearwindow,           nl,           write(" ********************************* "),nl,           write(" * 1. Read Database from file    * "),nl,           write(" * 2. Add new T-shirt in DB      * "),nl,           write(" * 3. Delete T-shirt from DB     * "),nl,           write(" * 4. Edit T-shirt in DB         * "),nl,           write(" * 5. Find T-shirt               * "),nl,           write(" * 6. Show all data              * "),nl,           write(" * 7. Write Database to file     * "),nl,           write(" * 8. Delete All DB              * "),nl,           write(" * 9. Exit                       * "),nl,           write(" ********************************* "),nl,           write(" Choose number 1-9 : "),           read_prov(Vibor),nl,           process(Vibor),Vibor = 9.

Далее опишем все эти функции.

Описание функций

Считывание базы данных из csv файла

Считывание базы данных из csv файла
Считывание базы данных из csv файла

process(1) — создаёт окно, где можно ввести имя csv файла из которого мы хотим считать базу данных. Считывание происходит за счет предиката read_rows(). При успешном считывании БД выводится сообщение «DB successfully read from file.». При неудаче выводится «Error reading file!». Затем, в обоих случаях, после нажатия пробела, происходит переход обратно в меню.

process(1) :-           makewindow(2,11,3,"Read data from file",2,20,15,40),shiftwindow(2),           write("Input File name (data.csv): "),           readln(Filename),            existfile(Filename),           openread(datafile, Filename),            readdevice(datafile),           read_rows(),           closefile(datafile), readdevice(keyboard),           write("DB successfully read from file."),nl,!,           write("Press space bar"), readchar(_),            removewindow, shiftwindow(1), clearwindow, menu;              write("Error reading file!"), nl, !,           write("Press space bar."),readchar(_),           removewindow, shiftwindow(1), clearwindow, menu, fail.

read_rows() — построчно считывает csv файл, при помощи восьми вызовов (у нас 8 параметров в базе данных) предиката front_string. После считывания каждой строки, вставляет полученные значения в конец базы данных dt_shirt, используя встроенный предикат assertz.

front_string(Line, Param, Tail) — считывает строку, пока не встретит csv разделитель ‑ ;

Имеет 3 параметра:

  1. Line — начальная строка

  2. Param — часть строки до первого разделителя ‑ ;

  3. Tail — оставшаяся строка после разделителя ‑ ;

read_rows() :-not(eof(datafile)),                 readln(Line),                 front_string(Line, F1_STR, Tail1),                  front_string(Tail1, F2_STR, Tail2), str_int(F2_STR, Price),                 front_string(Tail2, F3_STR, Tail3),                  front_string(Tail3, F4_STR, Tail4),                  front_string(Tail4, F5_STR, Tail5), str_int(F5_STR, Europe),                 front_string(Tail5, F6_STR, Tail6),                  front_string(Tail6, F7_STR, Tail7),                  front_string(Tail7, F8_STR, _), str_int(F8_STR, Year),                 assertz(dt_shirt(F1_STR,Price,F3_STR,F4_STR,Europe,F6_STR,F7_STR,Year)), !, read_rows();                                  not(eof(datafile)), !,                 write(" ********************************"), nl,                 write(" *        READING ERROR!        * "), nl,                 write(" * REMAINING DATA WAS NOT READ! * "), nl,                 write(" *     SOME MATERIALS ADDED!    * "), nl,                 write(" ******************************** "), nl; !.  front_string("", "", "") :- !. front_string(Line, Param, Tail) :-frontchar(Line, LineH, LineT),                                  LineH = ';', !,                                  Param = "", Tail = LineT;                                                                  frontchar(Line, LineH, LineT),                                  LineH <> ';', !,                                  front_string(LineT, T, Tail),                                  str_char(LineHS, LineH),                                 concat(LineHS, T, Param).

Добавление новой футболки в базу данных

Добавление новой футболки в базу данных
Добавление новой футболки в базу данных

process(2) — создаёт окно, где можно ввести параметры новой футболки. Ввод числовых значений происходит через предикат read_until_not_integer. После ввода всех параметров, они вставляются в конец базы данных dt_shirt, используя встроенный предикат assertz.

process(2) :-         makewindow(3,11,3,"Add data",2,20,18,58),shiftwindow(3),         write("Please, Input T-shirt:"),nl,         write("Name: "), readln(Name),         write("Price (RUB): "), read_until_not_integer(Price),         write("Sex: "), readln(Sex),         write("Size (International) : "), readln(World),         write("Size (Europe): "), read_until_not_integer(Europe),         write("Color: "), readln(Color),         write("Material: "), readln(Material),         write("Production year: "), read_until_not_integer(Year),         assertz(dt_shirt(Name,Price,Sex,World,Europe,Color, Material,Year)),         write(Name," added to DB"), nl,!,         write("Press space bar. "), readchar(_),         removewindow, shiftwindow(1), clearwindow, menu.

read_until_not_integer — проверяет, является ли введенное значение целым числом больше 0 или нет. Если не является, то вызывается повторно.

read_until_not_integer(Integer):-         readint(Integer),         Integer >=0, !;                  write("Enter integer number >=0: "),         read_until_not_integer(Integer).

Удаление футболки из базы данных

Удаление футболки из базы данных
Удаление футболки из базы данных

process(3) — создаёт окно, где можно ввести название футболки, которую необходимо удалить. После ввода названия футболки, она удаляется из базы данных dt_shirt, используя встроенный предикат retract.

process(3) :-         makewindow(4,11,3,"Delete data",10,30,7,40),shiftwindow(4),         write("Input T-shirt name: "), readln(Name),         retract(dt_shirt(Name,_,_,_,_,_,_,_)),         write(Name," removed from DB "), nl, !,         write("Press space bar."), readchar(_),          removewindow, shiftwindow(1);                  write("No data."),nl,!,         write("Press space bar."),readchar(_),         removewindow, shiftwindow(1).

Изменение информации о футболке

process(4) — создаёт окно, где можно ввести название футболки, информацию о которой необходимо изменить. После ввода названия футболки, она удаляется из базы данных dt_shirt, используя встроенный предикат retract. Далее вводятся все парам

process(4) :-           makewindow(5,11,3,"Edit data",2,20,18,58),shiftwindow(5),           write("Input T-shirt name: "), readln(Name1),           retract(dt_shirt(Name1,_,_,_,_,_,_,_)),           write("Name: "), readln(Name),           write("Price (RUB): "), read_until_not_integer(Price),           write("Sex: "), readln(Sex),           write("Size (International) : "), readln(World),           write("Size (Europe): "), read_until_not_integer(Europe),           write("Color: "), readln(Color),           write("Material: "), readln(Material),           write("Production year: "), read_until_not_integer(Year),           assertz(dt_shirt(Name,Price,Sex,World,Europe,Color, Material,Year)),nl, !,           write("Press space bar."), readchar(_),            removewindow, shiftwindow(1);                      write("No data."),nl,!,           write("Press space bar."),readchar(_),           removewindow, shiftwindow(1), clearwindow, menu.

Показать всю информацию о футболке

1-искать по названию; 2-искать по материалу
1-искать по названию; 2-искать по материалу
Поиск по названию (слева);                                                Поиск по материалу (справа)
Поиск по названию (слева); Поиск по материалу (справа)

process(5) — создаёт окно, где можно выбрать, как искать нужную футболку: 1 — по названию или 2 — по материалу. После вызывается предикат find, в котором происходит поиск футболки по выбранному нами параметру и затем выводится вся информация о ней.

process(5) :-         makewindow(6,11,3," Show T-shirt ", 2,30,22,47),  shiftwindow(6),         write("1. Find T-shirt by Name "),nl,         write("2. Find T-shirt by Material "),nl,          write(" Choose number 1-2 : "),         read_until_not_integer(N),          N>0,N<3,         find(N),         write("Press space bar"), readchar(_),          removewindow, shiftwindow(1), clearwindow, menu;          write("Wrong input."),nl,!,         write("Press space bar."),readchar(_),         removewindow, shiftwindow(1), clearwindow, menu.

find(1) — необходимо ввести название футболки, информацию о которой мы хотим получить. После ввода названия, вызывается предикат find_shirt_name, осуществляющий поиск футболки в базе данных. Если такое название было найдено, в консоль выводится вся информация о футболке. Если нет, то выводится сообщение «No such T-shirt in database!».

find(2) — аналогично find(1), только теперь необходимо ввести материал интересующей нас футболки.

find(1):-clearwindow, write("Input T-shirt name: "), readln(Name),                   find_shirt_name(Name), find_name(Name).  find(1):-write("No such T-shirt in database!").  find(2):-clearwindow, write("Input T-shirt material: "), readln(Material),                   find_material(Material), find_mat(Material).  find(2):-write("No such T-shirt in database!").  find(_):-write("Error ").  find_shirt_name(Name):-          dt_shirt(Name,Price,Sex,World,Europe,Color, Material,Year),nl,         write(" Name                : ",Name),nl,         write(" Price (RUB)         : ",Price),nl,         write(" Sex                 : ",Sex),nl,         write(" Size (International): ",World),nl,         write(" Size (Europe):      : ",Europe), nl,         write(" Color               : ",Color),nl,         write(" Material            : ",Material),nl,         write(" Production year     : ",Year),nl, nl, fail. find_shirt_name(_).  find_material(Material):-         dt_shirt(Name,Price,Sex,World,Europe,Color, Material,Year),nl,         write(" Name                : ",Name),nl,         write(" Price (RUB)         : ",Price),nl,         write(" Sex                 : ",Sex),nl,         write(" Size (International): ",World),nl,         write(" Size (Europe):      : ",Europe), nl,         write(" Color               : ",Color),nl,         write(" Material            : ",Material),nl,         write(" Production year     : ",Year),nl, nl, fail. find_material(_).  find_name(Name):-dt_shirt(Name,_,_,_,_,_,_,_). find_mat(Material):-dt_shirt(_,_,_,_,_,_,Material,_).

Показать все записи в базе данных

Показать все записи в базе данных
Показать все записи в базе данных

process(6) — создаёт окно, в котором выводятся все записи базы данных на экран. Для этого используется предикат write_all.

process(6) :-         makewindow(7,11,3," Show All data ", 0,0,25,80),  shiftwindow(7),         write("Name, Price(Rub), Sex, Size(Inter.), Size(Europe), Color, Material, Year"),         nl,         write("************************************************************************"),         nl,         write_all,         nl,!,         write("Press space bar."),readchar(_),         removewindow, shiftwindow(1), clearwindow, menu;                  write("No data."),nl,!,         write("Press space bar."),readchar(_),         removewindow, shiftwindow(1), clearwindow, menu.

write_all() — использует предикат findall(X,P,L), который собирает в список L все объекты X, удовлетворяющие цели P.

write_all([P1|T1], [P2|T2], [P3|T3], [P4|T4], [P5|T5], [P6|T6], [P7|T7], [P8|T8]) — выводит все значения найденные в базе данных через запятую.

write_all() :-     findall(P1, dt_shirt(P1,_,_, _,_,_,_,_), P1s),     findall(P2, dt_shirt(_,P2,_,_,_,_,_,_ ), P2s),     findall(P3, dt_shirt(_,_,P3, _,_,_,_,_), P3s),     findall(P4, dt_shirt(_,_,_,P4,_,_,_,_ ), P4s),     findall(P5, dt_shirt(_,_,_,_,P5,_,_,_ ), P5s),     findall(P6, dt_shirt(_,_,_,_,_,P6,_,_ ), P6s),     findall(P7, dt_shirt(_,_,_, _,_,_,P7,_), P7s),     findall(P8, dt_shirt(_,_,_, _,_,_,_,P8), P8s),     write_all(P1s, P2s, P3s, P4s, P5s, P6s, P7s, P8s);     writedevice(screen).  write_all([], [], [], [], [], [], [], []) :- !. write_all([P1|T1], [P2|T2], [P3|T3], [P4|T4], [P5|T5], [P6|T6], [P7|T7], [P8|T8]) :-           write(P1,", ",           P2," (RUB), ",           P3,", ",           P4,", ",           P5,", ",           P6,", ",           P7,", ",           P8),nl,           write("------------------------------------------------------------------------"),nl,           write_all(T1, T2, T3, T4, T5, T6, T7, T8).

Записать базу данных в файл csv

Записать базу данных в файл csv
Записать базу данных в файл csv
База данных в CSV файле
База данных в CSV файле

process(7) — создаёт окно, в котором необходимо ввести название файла для сохранения базы данных. После записывающее устройство ставится на файл — writedevice(datafile) и вызывается предикат write_all_csv, записывающий базу данных в файл.

process(7) :-         makewindow(8,11,3," Write Database to file ", 7,30,12,47),  shiftwindow(8),         write("Input file name (data.csv): "),         readln(Filename),         existfile(Filename), % Существует ли файл          openwrite(datafile, Filename),          writedevice(datafile),          write_all_csv,         closefile(datafile),          writedevice(screen),         write("DB successfully written to file."),         nl,!,         write("Press space bar."),readchar(_),         removewindow, shiftwindow(1), clearwindow, menu;                  write("Error writing file!"),nl,!,         write("Press space bar."),readchar(_),         removewindow, shiftwindow(1), clearwindow, menu.

write_all_csv() — устроен аналогично write_all(), только вместо запятых, параметры футболки разделяются символом — ;. Это необходимо для корректной записи в csv файл.

write_all_csv() :-     findall(P1, dt_shirt(P1,_,_, _,_,_,_,_), P1s),     findall(P2, dt_shirt(_,P2,_,_,_,_,_,_ ), P2s),     findall(P3, dt_shirt(_,_,P3, _,_,_,_,_), P3s),     findall(P4, dt_shirt(_,_,_,P4,_,_,_,_ ), P4s),     findall(P5, dt_shirt(_,_,_,_,P5,_,_,_ ), P5s),     findall(P6, dt_shirt(_,_,_,_,_,P6,_,_ ), P6s),     findall(P7, dt_shirt(_,_,_, _,_,_,P7,_), P7s),     findall(P8, dt_shirt(_,_,_, _,_,_,_,P8), P8s),     write_all_csv(P1s, P2s, P3s, P4s, P5s, P6s, P7s, P8s);     writedevice(screen).  write_all_csv([], [], [], [], [], [], [], []) :- !. write_all_csv([P1|T1], [P2|T2], [P3|T3], [P4|T4], [P5|T5], [P6|T6], [P7|T7], [P8|T8]) :-           write(P1,"; ",           P2,"; ",           P3,"; ",           P4,"; ",           P5,"; ",           P6,"; ",           P7,"; ",           P8),nl,     write_all_csv(T1, T2, T3, T4, T5, T6, T7, T8).

Удаление всех записей из базы данных

Удаление всех записей из базы данных
Удаление всех записей из базы данных

process(8) — создаёт окно, в котором при успешном удалении всех записей из базы данных, выведется сообщение «DB has been cleared». При ошибке выведется «Error writing file!».

process(8) :-         makewindow(9,11,3," Delete All DB ",10,30,7,40),  shiftwindow(9),         clear_database,         write("DB has been cleared"),         nl,!,         write("Press space bar."),readchar(_),         removewindow, shiftwindow(1), clearwindow, menu;                  write("Error writing file!"),nl,!,         write("Press space bar."),readchar(_),         removewindow, shiftwindow(1), clearwindow, menu.

clear_database — удаляет все факты из базы данных, используя встроенный предикат retract:

 clear_database:-           retract(dt_shirt(_,_,_,_,_,_,_,_)),           fail.  clear_database:-!.

Выход из программы

Выход из программы
Выход из программы

process(9) — очищает базу данных и выводит сообщение «See you again! «.

process(9) :-         clear_database,         write("See you again! "),readchar(_),exit.

Конец

Вот вроде и все.

Надеюсь вы нашли что искали)

Ссылка на исходный код: https://github.com/KirillTaE/Dynamic_DataBase_on_TurboProlog


ссылка на оригинал статьи https://habr.com/ru/post/716012/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *