Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Внутренние или динамические базы данных

Файлы

Строки

str_len – определение длины строки. Аргументы – строка, количество символов.

concat – соединение двух строк. Аргументы – строка1, строка2, результат.

frontchar – для разделение исходной строки а первый символ и хвост из оставшихся символов строки.

frontstr - аналогичен предыдущему, только позволяет отделить не один, а указанное количество символов. Аргументы – количество символов, которые копируются из второго параметра в третий, а в четвертый помещается остаток от второго параметра.

fronttoken – выделяет первый атом, входящий в строку. Атом это или идентификатор, или без знаковое число или символ.

isname – истинен, если его строковый аргумент является идентификатором и ложен в противном случае.

Предикат, который преобразует строку в список символов. Предикат будет иметь два аргумента. Первым аргументом будет данная строка, вторым — список, состоящий из символов исходной строки.

str_list("",[]). /* пустой строке соответствует

пустой список */

str_list(S,[H|T]):–

frontchar(S,H,S1),

/* H — первый символ строки S,

S1 — остаток строки */

str_list(S1,T).

/* T — список, состоящий

из символов, входящих

в строку S1*/

 

Предикат, преобразующий строку в список атомов:

str_a_list("",[]). /* пустой строке по-прежнему

соответствует пустой список */

str_a_list(S,[H|T]):–

fronttoken(S,H,S1),

/* H — первый атом строки S,

S1 — остаток строки */

str_a_list(S1,T).

/* T — список, состоящий

из атомов, входящих

в строку S1*/

 

Предикат преобразует список символов в строку. Предикат будет иметь два аргумента. Первым аргументом будет список символов, вторым — строка, образованная из элементов списка.

list_str([],""). /* пустой строке соответствует

пустой список */

list_str([H|T],S):–

list_str(T,S1),

/* S1 — строка, образованная

элементами списка T */

frontchar(S,H,S1).

/* S — строка, полученная

дописыванием строки S1

к первому элементу списка H */

 

Создадим предикат, который по строке и символу подсчитает количество вхождений этого символа в данную строку. Предикат будет иметь три аргумента: первые два — входные (строка и символ), третий — выходной (количество вхождений второго аргумента в первый).

char_count("",_,0). /* Любой символ не встречается

в пустой строке ни разу*/

char_count(S,C,N):–

frontchar(S,C,S1),!,

/* символ C оказался первым символом

строки S, в S1 — оставшиеся

символы строки S */

char_count(S1,C,N1),

/* N1 — количество вхождений

символа C в строку S1 */

N=N1+1.

/* N — количество вхождений

символа C в строку S получается

из количества вхождений символа C

в строку S1 добавлением единицы */

char_count(S,C,N):–

frontchar(S,_,S1),

/* первым символом строки S

оказался символ, отличный

от исходного символа C, в S1 —

оставшиеся символы строки S */

char_count(S1,C,N).

/* в этом случае количество

вхождений символа C в строку S

совпадает с количеством

вхождений символа C

в строку S1 */

Предикат, который по символу и строке возвращает первую позицию вхождения символа в строку, если символ входит в строку и 0, если не входит. Первые два — входные — символ и строка, третий — выходной — первая позиция вхождения первого параметра во второй параметр или ноль.

str_pos(C,S,1):–

frontchar(S,C,_),!.

/* Искомый символ C оказался первым

символом данной строки S */

str_pos(C,S,N):–

frontchar(S,_,S1),

/* S1 — состоит из всех символов

строки S, кроме первого, который

отличается от искомого символа C */

str_pos(C,S1,N1),

/* N1 — это позиция, в которой

символ C встречается первый раз

в хвосте S1 или ноль*/

N1<>0,!, /* если позиция вхождения

символа C в строку S1 не равна

нулю, то есть если он встречается

в строке S1, /

N=N1+1. /* то, увеличив позицию его

вхождения на единицу, мы получим

позицию его вхождения в исходную

строку */

str_pos(_,_,0). /* искомый символ не входит в данную

строку */

 

Предикат, который заменяет все вхождения одного символа на другой символ. У предиката будет четыре параметра. Первые три — входные (исходная строка; символ, вхождения которого нужно заменять; символ, которым нужно заменять первый символ); четвертым — выходным — параметром должен быть результат замены в первом параметре всех вхождений второго параметра на третий параметр.

str_replace("",_,_,""):–!. /* из пустой строки можно

получить только пустую

строку */

str_replace(S,C,C1,SO):–

frontchar(S,C,S1),!,

/* заменяемый символ C оказался

первым символом строки S,

S1 — остаток строки S */

str_replace(S1,C,C1,S2),

/* S2 — результат замены

в строке S1 всех вхождений

символа C на символ C1 */

frontchar(SO,C1,S2).

/* SO — результат склейки

символа C1 и строки S2 */

str_replace(S,C,C1,SO):–

frontchar(S,C2,S1),

/* разделяем исходную строку S

на первый символ C2

и строку S2, образованную

всеми символами строки S,

кроме первого */

str_replace(S1,C,C1,S2),

/* S2 — результат замены

в строке S1 всех вхождений

символа C на символ C1 */

frontchar(SO,C1,S2).

/* SO — результат соединения

символа C1 и строки S2 */

 

Предикат, который удаляет часть строки. Предикат будет иметь четыре параметра. Первые три входные: первый — исходная строка, второй — позиция, начиная с которой нужно удалять символы, третий — количество удаляемых символов. Четвертым — выходным — параметром будет результат удаления из строки, указанной в первом параметре, символов, в количестве, указанном в третьем параметре, начиная с позиции, указанной во втором параметре.

str_delete(S,I,C,SO):–

I1=I–1, /* I1 — количество символов,

которые должны остаться

в начале строки S */

frontstr(I1,S,S1,S2),

/* S1 — первые I1 символов

строки S, S2 — символы

строки S, с I —го

до последнего */

frontstr(C,S2,_,S3),

/* S3 — последние символы

строки S2 или, что тоже

самое, последние символы

строки S */

concat(S1,S3,SO).

/* SO — строка, полученная

соединением строк S1 и S3 */

 

Предикат, который копирует часть строки. Предикат будет иметь четыре параметра. Первые три входные: первый — исходная строка, второй — позиция, начиная с которой нужно копировать символы, третий — количество копируемых символов. Четвертым — выходным — параметром будет результат копирования символов из строки, указанной в первом параметре, в количестве, указанном в третьем параметре, начиная с позиции, указанной во втором параметре.

str_copy(S,I,C,SO):–

I1=I–1, /* I1 — это количество

символов, расположенных

в начале строки S, которые

не нужно копировать */

frontstr(I1,S,_,S1),

/* S1 — строка, состоящая

из всех символов строки S,

с I-го и до последнего */

frontstr(C,S1,SO,_).

/* SO — первые C символов

строки S1 */

 

Предикат, позволяющий вставить одну строку в другую. Предикат будет иметь четыре параметра. Первые три входные: первый — вставляемая строка; второй — строка, в которую нужно вставить первый аргумент; третий — позиция, начиная с которой нужно вставить первый параметр во второй. Четвертым — выходным — параметром будет результат вставки строки, указанной в первом параметре, в строку, указанную во втором параметре, начиная с позиции, указанной в третьем параметре.

str_insert(S,S1,I,SO):–

I1=I–1, /* I1 — это количество

символов, расположенных

в начале строки S, после

которых нужно вставить новые

символы */

frontstr(I1,S1,S1_1,S1_2),

/* S1_1 — первые I1 символов

строки S1, S1_2 — остаток

строки S1, с I —го и до

последнего */

concat(S1_1,S,S2),

/* S2 — строка, полученная

объединением строк S1_1

и S */

concat(S2,S1_2,SO).

/* SO — строка, полученная

слиянием строк S2 и S1_2 */

 

Предикат подсчитывающий количество цифр в строке. Предикат будет иметь всего два аргумента. Входным аргументом будет строка, количество цифр в которой нужно подсчитать, выходным аргументом будет количество цифр в первом аргументе.

dig(C,1):–

‘0’<=C,C<=’9’,!. /* C — цифра*/

dig(_,0).

count_digit("",0):–!. /* В пустой строке цифр нет */

count_digit(S,N):–

frontchar(S,C,S2),

/* C — первый символ строки S,

S2 — хвост строки S */

dig(C,M), /* M равен единице, если C —

цифра, и нулю — иначе */

count_digit(S2,N2),

/* N2 — количество цифр

в строке S2*/

N=N2+M. /* Количество цифр во всей

строке больше на единицу,

чем количество цифр

в хвосте, если первый символ

строки — цифра, и равно

количеству цифр в хвосте —

иначе */

Файлом называют именованную совокупность данных, записанных на диске. Файл состоит из компонентов. При чтении или записи файловая переменная перемещается по очередному компоненту и делает его доступным для обработки. В прологе пользовательские файлы описываются в разделе описания доменов следующим образом:

file = <символическое имя файла1>;...;

<символическое имя файлаN>

 

Символические имена файлов называют внутренними или логическими именами в отличие от внешних или физических имен файлов. Символическое имя файла должно начинаться со строчной буквы. Кроме пользовательских файлов имеются стандартные файлы, которые не нужно описывать в разделе описания доменов.

Это:

  • stdin(стандартное устройство ввода);
  • stdout(стандартное устройство вывода);
  • stderror(стандартное устройство вывода сообщений об ошибках);
  • keyboard(клавиатура);
  • screen(монитор);
  • printer(параллельный порт принтера);
  • coml(последовательный порт).

По умолчанию стандартным устройством ввода является клавиатура, а вывода – монитор. Чтобы начать работу с пользовательским файлом, его нужно открыть, а по завершении работы закрыть. Стандартное устройство открывать и закрывать не нужно. Встроенные предикаты для работы с файлами:

Openread – открывает только для чтения.
OpenWrite – только для записи.
OpenAppend – запись в конец файла
OpenModify – чтение и запись одновременно
ExistFile – истинен если файл с указанным именем существует

“C:\\Prolog\\BIN”

CloseFile – закрытие файла
RenameFile – переименовать файл
DeleteFile – удалить файл
Disk – задает текущий диск или каталог
Dir – выбор из списка файлов
eof – истинен если достигнут конец файла
FilePos – текущая позиция чтения или записи в файле или изменить её. Первый аргумент символическое имя, второй – позиция внутри файла, третий - номер режима, который задает откуда отсчитывается позиция (0 – начало, 1 – текущая, 3 - конец)
ReadDevice – используется для переопределения текущего устройства ввода или чтобы узнать, какое устройство является текущим.
WriteDevice – используется для переопределения текущего устройства вывода или для получения имени текущего устройства вывода.
Write – предикат для записи данных в текущее устройство
ReadLn – чтение строки и з текущего устройства
ReadInt – читает целое число

Readreal - читает вещественное число

ReadChar – читает символ

ReadTerm – читает терм
File_str – читает символы файла в строку или, наоборот, записывает содержимое строки в файл, в зависимости от того, свободен ли второй параметр этого предиката
Flush – используется для принудительной записи в файл содержимого внутреннего буфера, выделенного для файла, указанного в его единственном параметре
FileMode – задает режим доступа к файлу(0 – бинарный режим, 1 - текстовый)

 

Пример. Предикат, выводящий содержимое произвольного файла на экран. Параметр – внешнее дисковое имя файла.

DOMAINS /* раздел описания доменов */

file = f /* f — внутреннее имя файла */

PREDICATES /* раздел описания предикатов */

write_file(file)

writeFile(string)

CLAUSES /* раздел описания предложений */

write_file(f):–

not(eof(f)),!, /* если файл f еще

не закончился */

readchar(C), /* читаем из него символ */

write(C," "), /* выводим символ на экран*/

write_file(f). /* продолжаем процесс */

write_file(_). /* это предложение нужно, чтобы предикат

не потерпел неудачу в случае, когда

будет достигнут конец файла */

writeFile(F_N):–

existfile(F_N),!, /* убеждаемся в существовании

файла с именем F_N */

openread(f,F_N), /* связываем внешний файл F_N

с внутренним файлом f

и открываем его на чтение */

readdevice(f), /* устанавливаем в качестве

устройства чтения файл f */

write_file(f), /* вызываем предикат, выводящий

на экран все символы

файла f */

closefile(f), /* закрываем файл */

readdevice(keyboard), /* перенаправляем ввод

на клавиатуру */

nl,nl, /* пропускаем строку */

write("Нажмите любую клавишу"),

/* выводим сообщение на экран */

readchar(_)./* ждем нажатия любой клавиши */

writeFile(F_N):–

write("Файл с именем ",F_N," не наден!").

/* выдаем сообщение, если предикат

existfile потерпел неудачу */

GOAL /* раздел описания внутренней цели*/

write("Введите имя файла: "),

readln(F_N), /* читаем название файла в переменную F_N */

writeFile(F_N).

 

Пример. Формирование файла из символов с клавиатуры.

DOMAINS

file=f

PREDICATES

Readfile

CLAUSES

readfile:–

writedevice(screen), /* назначаем текущим

устройством записи

экран */

write("Введите символ (# — конец ввода)"), nl,

/* выводим сообщение */

readchar(C), /* читаем символ с клавиатуры */

write(C), /* дублируем символ на экран */

C<>'#',!, /* если это не #*/

writedevice(f), /*, то перенаправляем вывод

в файл */

write(C), /* записываем символ в файл */

readfile.

readfile:–

closefile(f). /* если введенный символ оказался

равен символу '#', то закрываем файл */

GOAL

write("Введите имя файла: "),

readln(F_N),

/* читаем название файла в переменную F_N */

openwrite(f,F_N), /* связываем внешний файл F_N

с внутренним файлом f и открываем

его на запись */

readfile(f).

 

Пример. Предикат, который переписывает один файл в другой так, чтобы в другом файле все английские буквы были большими.

transform:–

not(eof(f)),!, /* если файл f еще

не закончился */

readln(S), /* читаем из файла f строку

в переменную S */

upper_lower(S_U,S),

/* S_U — результат преобразования

всех символов строки S в верхний

егистр */

write(S_U),nl, /* записываем строку S_U

в файл f_o */

transform. /* продолжаем процесс */

transform:–

closefile(f), /* закрываем файл f */

closefile(f_o). /* закрываем файл f_o */

upper_file(N_F,N_o_F):–

existfile(N_F),!, /* проверяем существование

файла с именем N_F */

openread(f,N_F), /* связываем внешний файл

с именем N_F с внутренним

файлом f и открываем его

на чтение */

readdevice(f), /* устанавливаем в качестве

текущего устройства чтения

файл f */

openwrite(f_o,N_o_F),

/* связываем внешний файл с именем

N_o_F с внутренним файлом f

и открываем его на запись */

writedevice(f_o), /* устанавливаем в качестве

текущего устройства записи

файл f_o */

transform. /* вызываем вспомогательный

предикат */

upper_file(N_F,_):–

write("Файл с именем ",N_F," не найден!").

/* выдаем сообщение, если предикат

existfile был неуспешен */

На прологе легко реализуются реляционные базы данных. Любая таблица такой базы данных может быть описана соответствующим набором фактов, где каждой записи исходной таблицы будет соответствовать один факт, а каждому полю – аргумент предиката, реализующего таблицу. Turbo Prolog имеет встроенные средства для работы с внутренними и внешними базами данных. Внутренние базы данных обрабатываются исключительно в оперативной памяти, в отличие от внешних баз данных. Внутренняя база данных состоит из фактов, которые можно динамически в процессе выполнения программы добавлять в базу данных и удалять из неё, сохранять в файле и загружать факты из файла. Эти факты могут использовать только предикаты, описаные в разделе описания предикатов базы данных.

DATABASE [ — <имя базы данных>]

<имя предиката>(<имя домена первого аргумента>,...,

< имя домена n-го аргумента>)

...

 

Если раздел описания базы данных в программе только один – то он может не иметь имени (стандартное имя dbasedom). В базе данных могут содержаться только факты, а не правила вывода. Факты базы данных не могут содержать свободных переменных.

Существуют встроенные предикаты, предназначенные для работы с внутренней базой данных:

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

asserta – добавляет факт перед другими фактами.

assertz – добавляет факт после других фактов.

assert – добавлен для совместимости с другими версиями Пролога и работает точно так же, как и assertz.

Для удаления служат предикаты retract и retractall. Чтобы удалить всё используется retractall с анонимной переменной.

Для сохранения динамической базы на диске служит предикат save – сохранение в текстовый файл.

Факты, сохранённые в текстовом файле на диске, могут быть загружены в оперативную память предикатом consult.

Каждый факт в таком файле должен занимать отдельную строку, количество аргументов и их тип должны соответствовать описанию предиката в разделе database.

Пример. Программа, реализующая компьютерный вариант телефонного справочника. Находит по фамилии человека его телефонный номер или, наоборот, по телефонному номеру — фамилию владельца телефона. В программе будет 5 операций:

· Получение информации о телефонном номере по фамилии человека.

· Получение информации о фамилии абонента по телефонному номеру.

· Добавление новой записи в телефонную базу.

· Изменение существующей в телефонной базе записи.

· Удаление записи из телефонной базы.

DOMAINS /* раздел описания доменов */

name, number = String /* фамилию абонента и телефонный

номер будем хранить в виде

строк */

file=f /* файловый домен будем использовать для

считывания с диска и записи на диск нашей

телефонной базы */

DATABASE /* раздел описания предикатов внутренней

базы данных */

phone(name, number)

PREDICATES /* раздел описания предикатов */

name_phone(name, number) /* этот предикат находит номер

телефона по фамилии абонента */

phone_name(name, number) /* этот предикат находит фамилию

абонента по номеру телефона */

m(char) /* этот предикат реализует выполнение

соответствующего пункта меню */

menu /* этот предикат реализует вывод меню и

обработку выбора пользователя */

start /* этот предикат проверяет наличие файла

с телефонной базой на диске и либо загружает

факты из нее во внутреннюю базу данных,

если такой файл существует, либо создает

этот файл, если его не было */

CLAUSES /* раздел описания предложений */

name_phone(Name,Phone):–

phone(Name,Phone),!.

name_phone(_,"Нет информации о телефонном номере").

/* если соответствующего факта

во внутренней базе данных не нашлось,

вместо телефонного номера возвращаем

соответствующее сообщение */

phone_name(Name,Phone):–

phone(Name,Phone).

phone_name("Нет информации о владельце телефона",_).

/* если соответствующего факта

во внутренней базе данных не нашлось,

вместо фамилии абонента возвращаем

соответствующее сообщение */

menu:–

clearwindow, /* очистка текущего окна */

write("1– Получение телефонного номера

по фамилии "),nl,

write("2 — Получение фамилии абонента по номеру

телефона "),nl,

write("3 — Добавление новой записи в телефонную

базу."),nl,

write("4 — Изменение номера абонента"),nl,

write("5 — Удаление записи из телефонной базы"),nl,

write("0 — Выйти"),nl,

readchar(C), /* читаем символ с клавиатуры */

m(C). /* вызываем выполнение соответствующего пункта

меню */

m('1'):–

clearwindow,

write("Введите фамлию"), nl,

readln(Name),

name_phone(Name, Phone),

write("Номер телефона: ",Phone),

readchar(_),

menu.

m('2'):–

clearwindow,

write("Введите номер телефона"),nl,

readln(Phone),

phone_name(Name, Phone),

write("Фамилия абонента: ",Name),

readchar(_),

menu.

m('3'):–

clearwindow,

write("Введите фамилию"),nl,

readln(Name),

write("Введите номер телефона"),nl,

readln(Phone),

assert(phone(Name,Phone)),

/* добавляем факт во внутреннюю

базу данных */

menu.

m('4'):–

clearwindow,

write("Введите фамилию"),nl,

readln(Name),

write("Введите новый номер телефона"),nl,

readln(Phone),

retract(phone(Name,_)),

/* удаляем устаревшую информацию

из внутренней базы данных */

assert(phone(Name,Phone)),

/* добавляем новую информацию

в телефонную базу */

menu.

m('5'):–

clearwindow,

write("Укажите номер телефона, запись о котором

нужно удалить из телефонной базы"), nl,

readln(Phone),

retract(phone(_,Phone)), /* удаляем соответствующий

факт из внутренней базы

данных */

menu.

m('0'):–

save("phones.ddb "), /* сохраняем телефонную базу

в файл */

retractall(_)./* удаляем все факты из внутренней

базы данных */

m(_):–

menu. /* если пользователь по ошибке нажал клавишу,

отличную от тех, реакция на которые

предусмотрена, ничего плохого

не произойдет, будет отображено меню

еще раз */

start:–

existfile("phones.ddb"),!, /* если файл с телефонной

базой существует */

consult("phones.ddb "), /* загружаем факты во

внутреннюю базу данных */

menu. /* вызываем меню */

start:–

openwrite(f,"phones.ddb"),

/* если файла с телефонной

базой не существует, создаем

его */

closefile(f),

menu. /* вызываем меню */

GOAL /* раздел внутренней цели*/

Start

 

Пример. Повышение эффективности программ за счет добавления уже вычисленных фактов в базу данных. При попытке вычислить предикат сначала проверяется, нет ли в базе данных уже вычисленного значения, и если оно там уже есть, то просто берется это значение. Если же ответа еще нет, он вычисляется обычным способом, после чего добавляется в базу данных для повторного использования. Эта техника еще называется мемоизация или табулирование.

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

fib2(0,1):–!. /* нулевое число Фиббоначи равно единице */

fib2(1,1):–!. /* первое число Фиббоначи равно единице */

fib2(N,F):–

fib_db(N,F),!. /* пытаемся найти N-е число

Фиббоначи среди уже

вычисленных чисел, хранящихся

во внутренней базе данных */

fib2(N,F):–

N1=N–1, fib2(N1,F1), /* F1 это N–1-е число

Фиббоначи */

N2=N–2, fib2(N2,F2), /* F2 это N–2-е число

Фиббоначи */

F=F1+F2, /* N-е число Фиббоначи равно сумме

N–1-го числа Фиббоначи и N–2-го

числа Фиббоначи */

asserta(fib_db(N,F)).

/* добавляем вычисленное N-е число

Фиббоначи в нашу внутреннюю базу

данных*/

<== предыдущая лекция | следующая лекция ==>
Деревья. Деревами называется граф, у которого одна вершина корневая, а остальные вершины имеют только одного отца и все вершины являются потомками корневой вершины | Пролог и искусственный интеллект
Поделиться с друзьями:


Дата добавления: 2014-01-07; Просмотров: 441; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.221 сек.