Опубликован: 12.02.2014 | Доступ: свободный | Студентов: 818 / 236 | Длительность: 11:22:00
Специальности: Программист
Лекция 4:

Внутренняя база данных

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >

4.5. Внутренняя база фактов

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

Объявление базы фактов

Внутренняя база данных объявляется следующим образом:

class facts - rel 
    супруг: (string Муж, string Жена).

База данных имеет имя rel. Имена внутренних баз данных принадлежат домену factDB. База данных может не иметь имени. В имплементации одного и того же класса может быть несколько безымянных внутренних баз данных. Но если требуется загружать базу данных из файла или сохранять ее в файле, она должна иметь имя.

Добавление фактов

Предикат asserta добавляет факт в начало базы данных:

asserta(супруг(Муж, Жена)).

Предикаты assert и assertz добавляют факт в конец базы данных:

assert(супруг(Муж, Жена)).

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

Удаление фактов

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

Предикат retract может возвращать значения, хранящиеся в удаляемых фактах. Например, цикл

retract(супруг(Муж, _)), write(Муж), nl, fail.

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

Предикат retractAll удаляет все факты, которые унифицируются с аргументом этого предиката. Этот предикат всегда успешный, значения аргументов он не возвращает:

retractAll(супруг(Муж, _)).

Предикат retractFactDb удаляет все записи из базы данных:

retractFactDb(rel).
Загрузка базы данных из файла и запись в файл

Сохранение в файл фактов базы данных выполняет предикат save:

file::save("family.txt", rel)

Если указанного файла нет, то он будет создан.

Предикат consult загружает факты базы данных из файла, при этом они добавляются к текущему состоянию базы данных:

file::consult("family.txt", rel)
Предикат reconsult заменяет текущее состояние базы данных фактами из файла:
file::reconsult("family.txt", rel)

Следующая программа — это пример работы с внутренней базой данных, изменения в которую вносятся во время исполнения программы посредством диалога с пользователем. Для организации диалога применяется repeat-цикл. Выход из цикла производится только при выборе пользователем команды "Выход". Для обработки ошибок используется конструкция try-catch.

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

class facts - phones
    phone: (string Имя, string НомерТелефона).

class predicates
    load: (string FileName).
    maindialog: ().
    act: (string НомерДействия) determ.
    add: (string Name, string Phone).
    delete: (string Name).
    delete: (string Name, string Phone).
    ask: (string Name [out], string Phone [out]) determ.
    ask: (string Name [out]) determ.
    printDb: ().
clauses
    load(FileName):-
        file::existFile(FileName),
        !,
        try file::consult(FileName, phones)	% обработка ошибок
        catch Error do
            writef("Error %. Unable to load the database from "
                "the file %\n", Error, FileName)
        end try;
        succeed().

    maindialog():-
        std::repeat(),
            write("\nВыберите действие:\n",
                "\t1. Просмотр базы данных\n",
                "\t2. Добавить запись\n",
                "\t3. Удалить запись\n",
                "\t4. Выход\n"),
            X = readLine(),
        act(X),
        !.
    maindialog().

    act("1"):- !,
        write("\nВсе записи\n"),
        printDb(),
        fail.
    act("2"):- !,
        write("\nДобавление записи"),
        ask(Name, Phone),
        add(Name, Phone),
        fail.
    act("3"):- !,
        write("\nУдаление записей. Выберите действие:\n",
            "\t3.1 Удаление одной записи\n",
            "\t3.2 Удаление всех записей\n"),
        X = readLine(),
        act(X).
    act("3.1"):- !,
        printDb(),
        ask(Name, Phone),
        delete(Name, Phone),
        fail.
    act("3.2"):- !,
        ask(Name),
        delete(Name),
        fail.
    act("4"):- !, write("\nВыход.\n").
    act(_):- 
        X = readLine(), 
        act(X).

    printDb():-
        phone(Name, Phone),
            writef("  %-20%\n", Name, Phone),
        fail;
        succeed().
 
    ask(Name, Phone):-
        ask(Name),
        write("Введите номер: "),
        Phone = string::trim(readLine()).

    ask(Name):-
        write("\nВведите имя: "),
        Name = string::trim(readLine()),
        Name <> "".

    add(Name, Phone):-
        phone(Name, Phone),
        !,
        writef("Запись % - % уже есть в базе данных\n", 
            Name, Phone);
        assert(phone(Name, Phone)),
        writef("Запись '% - %' добавлена\n", Name, Phone).

    delete(Name):-
        not(phone(Name, _)),
        !,
        writef("Записей для '%' нет\n", Name);
        retractall(phone(Name, _)),
        writef("Записи для '%' удалены\n", Name).

    delete(Name, Phone):-
        retract(phone(Name, Phone)),
        !,
        writef("Запись '% - %' удалена\n", Name, Phone);
        writef("Записи '% - %' нет в базе данных\n", Name, Phone).

    run():-
        setConsoleTitle("Телефоны"),
        FileName = "phones.txt",
        load(FileName),
        maindialog(),
        file::save(FileName, phones),
        _ = readLine().
Пример 4.3. База данных "Телефоны"

Файл "phones.txt" создается в директории Exe проекта. Предикат setConsoleTitle устанавливает заголовок окна консоли, предикат writef выполняет форматированный вывод. Предикат trim удаляет пробельные символы в начале и в конце строки. Предикат existFile проверяет, существует ли указанный файл.

Упражнение 2. Добавьте в программу про телефоны (листинг 4.3) поиск номеров телефонов по имени и поиск имени по номеру телефона.

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >
Жаныл Айкын
Жаныл Айкын
Rustam Inatov
Rustam Inatov

Доброго времени суток, подскажите пожалуйста, visual prolog examples, pie, vip7.5 - это все, где я могу скачать? (в смысле) может быть на сайте есть какой-то архив? Увы я не нашел его.

Подскажите, пожалуйста.

С уважением, Рустам.