Как стать автором
Поиск
Написать публикацию
Обновить

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

Уровень сложностиСредний
Время на прочтение11 мин
Количество просмотров6.5K

Теория

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

  • раздел 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

Теги:
Хабы:
Всего голосов 20: ↑20 и ↓0+20
Комментарии12

Публикации

Ближайшие события