В папке с установленным SWI/PROLOGвойдите в директориюpl/bin, содержащую файлplwin.exe, и запустите его. На экране появится главное меню и главное (диалоговое) окно с приглашениемSWI/PROLOG (см рис.1).
Рис.1Вид диалогового окнаSWI/PROLOG Главное меню можно сделать активным, нажав F10илиAlt. Когда главное меню активно, его элементы можно выбрать с помощью клавиш управления курсором (
) и последующим нажатием клавишиEnter. Выбирать элементы главного меню можно также и мышью.
Первая программа
Программана Прологе состоит из фактовиправил, которые образуютбазузнанийПролог-программы, изапросак этой базе, который задаетцельпоиска решений.Предикатописывают отношение между объектами, которые являются аргументами предиката.
ФактыКонстатируют наличие заданного предикатом отношения между указанными объектами. ПРИМЕР Констатация факта в предложениии Эллен любит теннис. в синтаксисе Пролога выглядит так:
Введение в программирование на языке Prolog. Решение варианта задачи.
Кириллица используется наравне с латинскими буквами. Обычно предикатам дают такие имена, чтобы они отражали смысл отношения. Например:main, add_file_name. Два предиката могут иметь одинаковые имена, тогда система распознает их как разные предикаты, если они имеют различное число аргументов (арность). Например, любит/2, любит/3.
Имя предиката может совпадать с именем какого-либо встроенного предиката SWI/PROLOG-а. Однако, если совпали имена пользовательского и встроенного предиката, то при обращении к нему (либо из интерпретатора, либо из программы), будет вызван пользовательский предикат, т.е. пользовательское определение «перекроет» предопределенное вSWI/PROLOG-е.
Правилаописывают связи между предикатами. ПРИМЕР Билл любит все, что любит Том. в синтаксисе Пролога любит(‘Билл’,Нечто):- любит(‘Том’,Нечто). Правило B:-Aсоответствует импликацииA→B(«ЕСЛИA, ТОB»).
В общем виде правило- это конструкция вида: P0:-P1,P2,…,Pn. которая читается «P0истинно, еслиP1иP2и . Pnистинны».
Предикат P0называетсязаголовком правила, выражениеP1,P2,…,Pn-телом правила, а предикатыPi-подцелями правила.Запятаяозначает логическое «И». Факты и правила называются также утверждениямииликлозами. Факт можно рассматривать как правило, имеющее заголовок и пустое тело.
Процедура- это совокупность утверждений, заголовки которых имеют одинаковый функтор и одну и ту же арность. Процедура задает определение предиката. Конец предложения всегда отмечается точкой, поэтому все факты, правила и запросы должны заканчиваться точкой. Заметим также, что между именем предиката и скобкой не должно быть пробелов.
Пролог — примеры списков
Переменная- поименованная область памяти, где может храниться значение. Если переменная не связана со значением – она называется свободной переменной. Унификация- процесс получения свободной переменной значения в результате сопоставления при логическом выводе в SWI/PROLOG-е.
Понятие переменной в логическом программировании отличается от базового понятия переменной, которое вводится в структурном программировании. Прежде всего, это отличие заключается в том, что переменная в SWI/PROLOG-е, однажды получив свое значение при унификации в процессе работы программы, не может его изменить, т.е. она скорее является аналогом математического понятия «переменная» – неизвестная величина.
Переменная вSWI/PROLOGне имеет предопределенного типа данных и может быть связана с значением любого типа данных. Переменная в SWI/PROLOGобозначается как последовательность латинских букв, кириллицы и цифр, начинающаяся с заглавной буквы или символа подчеркивания ( _ ). Заметим, что если значение аргумента предиката или его имя начинается с заглавной буквы, то оно пишется в апострофах (см. предыдущий пример).
В SWI/PROLOGразличаются строчные и заглавные буквы. Рассмотрим следующую программу на SWI/PROLOG, которую будем использовать для иллюстрации процессов создания, выполнения и редактирования Пролог-программ.
ПРОГРАММА 1. /* кто что любит */ любит(‘Эллен’,теннис). %Эллен любит теннис любит(‘Джон’,футбол). %Джон любит футбол любит(‘Том’,бейсбол). %Том любит бейсбол любит(‘Эрик’,плавание). %Эрик любит плавание любит(‘Марк’,теннис). %Марк любит теннис любит(‘Билл’,X):-любит(‘Том’,X). %Билл любит то, что любит Том Комментарий в строке программы начинается с символа % и заканчивается концом строки. Блок комментариев выделяется специальными скобками: /* (начало) и */ (конец).
-
Для того чтобы набрать текст программы воспользуйтесь встроенным текстовым редактором. Чтобы создать новый файл выберете команду File/New, в диалоговом окне укажите имя нового файла, например,тест. Для редактирования уже созданного файла с использованием встроенного редактора можно воспользоваться командой меню File/Edit.
Набейте программу 1 (текст программы выше по тексту) и сохраните ее (File/Savebuffer). Внешний вид редактора Красным цветом подсвечиваются предикаты в заголовках предложений, которые с точки зрения синтаксиса SWI/PROLOGа корректны.
Указатель “курсор” можно использовать для выверки (например, корректности) расстановки скобок. Зелёным цветом выделяются комментарии ,темно-красным цветом — переменные. Подчеркиванием выделяются предикаты в теле правила, которые совпадают с предикатом заголовка,- таким образом акцентируется внимание на возможном зацикливании программы.
Чтобы запустить программу, сначала необходимо ее загрузить в SWI/PROLOGдля выполнения. Это делается выбором опцииCompile/Compilebufferиз окна редактора. Результат компиляции отображается в окне интерпретатораSWI/PROLOGа. Там же указываются ошибки, возникшие при компиляции, чаще всего они отображаются и во всплывающем окне ошибок.
Обычно перед компиляцией предлагается сохранить файл. Другой способ загрузить уже существующий файл – это выполнение команды Consultв подменюFileдиалогового окнаSWI/PROLOG. На экране появится диалоговое окно.
Если вы попытаетесь загрузить для выполнения файл, в котором есть синтаксические ошибки, то он не загрузится, а вы получите сообщение об ошибке в главном окне. Угловые скобки>будут выделять место, где встретилась ошибка. По умолчанию файлы, ассоциируемые сSWI/PROLOGимеют расширение.pl.
Файлы также можно загрузить, используя встроенный предикат: consult(Имя файла или имена нескольких файлов). ПРИМЕРЫ consult(Test). % test – имя файла consult([Test1,Test2]). % Загрузка двух файлов. consult(‘test.pl’). 1 Для выполнения загрузки этот предикат нужно написать в главном окне после приглашения интерпретатора (?-), которое означает, что интерпретатор ждет запрос.
Запрос- это конструкция вида:?- P1,P2,…,Pn.которая читается «Верно ли P1иP2и . Pn?». ПредикатыPiназываютсяподцелями запроса. Запрос является способом запуска механизма логического вывода, т.е фактически запускает Пролог-программу.
Для просмотра предложений загруженной базы знаний можно использовать встроенный предикат listing. Проверьте загрузку исходного файла, задайте запрос ?-listing. Введите запрос: ?-любит(‘Билл’,бейсбол). % Любит ли Билл бейсбол? Получите ответ yes(да) и новое приглашение к запросу.
Введите следующие запросы и посмотрите на результаты. ?-любит(‘Билл’,теннис).%Любит ли Билл теннис? ?-любит(Кто, теннис). %Кто любит теннис? ?-любит(‘Марк’,Что),любит(‘Эллен’,Что).%Что любят Марк и Эллен? ?-любит(Кто, Что). %Кто что любит? ?-любит(Кто, _). %Кто любит? При поиске решений в базе Пролога выдается первое решение. ПРИМЕР ?-любит(Кто,теннис).
Кто = ‘Эллен’ Если необходимо продолжить поиск в базе по этому же запросу и получить альтернативные решения, то вводится точка с запятой ;. Если необходимо прервать выполнение запроса, (например, нужно набрать другой запрос), используйте клавишу b. Если Вы хотите повторить один из предыдущих запросов, воспользуйтесь клавишами «стрелка вверх» или «стрелка вниз».
Перезагрузить, измененные во внешнем редакторе, файлы можно, используя встроенный предикат make. Например так: ?-make. Перезагружаются все измененные файлы и файл начальной инициализации pl.ini; о его назначении будет оговорено позднее.
Источник: studfile.net
Как работать в SWI Prolog
Если у вас возникают проблемы с пониманием того, как вообще выполняются программ на Prolog — посмотрите статью: Введение в логическое программирование. В этой статье описан процесс установки SWI Prolog и запуска простой программы в консоли (терминале) с помощью утилицы swipl. Однако, для SWI Prolog есть несколько сред разработки.
Установка SWI Prolog
Я буду устанавливать SWI Prolog на 64х разрядную версию OpenSUSE 42.1. Для установки открываем центр управления Yast:
Выбираем «Управление программным обеспечением». В появившемся окне вводим swipl, в правой части окна появляется соответствующий пакет, нажимаем на него правой кнопкой мыши и выбираем «установить»:
Теперь для работы в среде SWI Prolog можно открыть терминал и ввести команду swipl. Будет запущен интерпретатор, в который можно передавать команды:
Программирование в SWI Prolog
Для присоединения файлов с исходным кодом можно выполнить команду consult(путь к файлу) или [путь к файлу] . Немного удобнее использовать редактор кода (например kate или gedit) со встроенным окном терминала (для этого во многих редакторах есть специальные плагины):
Для работы нужно открыть в редакторе файл исходного кода, в терминале перейти в соответствующий каталог и выполнить в нем команду swipl , присоединить файл исходного кода при помощи consult . Теперь можно передавать интерпретатору команды. В приведенном выше примере, в файле описаны студенты в соответствии с заданием, мы выполняем команду student(Who, Rate) для получения информации обо всех студентах в базе. В отличии от Visual Prolog, SWI Prolog не выводит сразу все найденные решения. Выводится первое решение, при этом если полученных данных пользователю достаточно, он может ввести точку, а если ему нужны другие решения — то нужно ввести точку с запятой. Введем в текстовом редакторе программу в соответствии с заданием:
student(‘Ivanov’, 4.5). student(‘Fedorov’, 3). student(‘Vetrov’, 4.3). student(‘Petrov’, 3.2). student(‘Popov’, 4.6). student(‘Sidorov’, 5). stipendiya(Name):- student(Name, SrBal), SrBal > 4. company(‘Microsoft’, 5). company(‘Apple’, 4.9). company(‘IBM’, 4.5). company(‘Samsung’, 4). company(‘Maxim = SrBalCompany.
Для обновления данных в интерпретаторе нужно повторно выполнить команду consult. Разберем предложенную программу:
- предикаты company и student являются фактами (подобно предикату parent из предыдущей работы);
- предикат stipendya принимает имя студента, выполняет поиск студента в базе и получение его среднего балла. Затем выполняется сравнение среднего балла с константой:
- если сравнение проходит успешно, то предикат также завершится успешно и «снаружи» мы получим имя студента, для которого есть стипендия;
- если при сравнении выясняется, что балл студента меньше константы, то предикат завершается неудачей. Никакого результата (информации о студенте, с которым это случилось) «снаружи» мы при этом не получим, но будет запущен механизм поиска с возвратами (интерпретатор попробует подобрать других студентов, соответствующих нашим критериям);
- предикат может завершиться неудачей до выполнения сравнения — если передано имя студента, о котором нет информации в базе (мы просто не сможем получить для него средний балл);
- наконец, если в предикат передана анонимная переменная stipendya(Name) , то будут выведены все студенты, для которых начисляется стипендия.
Чтобы составить запрос относительно получения стипендии студентом Поповым достаточно передать имя студента в качестве аргумента правилу stipendya . При выполнении такого запроса мной были получены ошибки:
.
Интерпретатор сообщает, что нет такого предиката в нашей программе. На самом деле, в программе содержится опечатка (имя функции написано неверно). После исправления ошибки и перекомпиляции программы командой [имя файла] или consult(имя файла) ошибка исправлена, получен ответ true , означающий, что студенту Попову положено получать стипендию.
Аналогично выполняется проверка получения стипендии студентом Федоровым (которому стипендия не положена, поэтому выводится false ):
Чтобы получить имена всех студентов, получающих стипендию передадим в качестве аргумента функции stipendiya анонимную переменную:
Чтобы получить минимальный средний балл, необходимый для трудоустройства в Microsoft нужно выполнить запрос company(‘Microsoft’, X) . Во время его выполнения нужная информация будет получена непосредственно из факта company(‘Microsoft’, 5) . Результат:
Чтобы проверить может ли Попов трудоустроиться в Microsoft нужно использовать предикат isAbleToWork :
Чтобы узнать организации, в которые может устроиться на работу Федоров, нужно передать имя студента в isAbleToWork , но в качестве названия компании передать анонимную переменную:
Чтобы получить имена студентов, способных устроиться в Apple, нужно наоборот передать в isAbleToWork имя компании, а вместо имени студента указать переменную без присвоенного заранее значения:
Аналогичный запрос, но с именем компании IBM нужно выполнить для поиска студентов, которые могут трудоустроиться в эту компанию. Результаты отличаются тем, что устроиться может несколько студентов. Для получения всех студентов нужно вводить точку с запятой после каждого результата:
Выводы: во время выполнения работы были получены навыки работы в среде SWI-Prolog Исследован код программы, выданный преподавателем; во время выполнения заданий получены некоторые навыки отладки программ в интерпретаторе SWI-Prolog.
Источник: pro-prof.com
SWI-Prolog. Ваша третья программа
Итак, вот текст программы. Допустим, он хранится в файле animal.pl:
% собаки dog(sharik). % дословно означает, что Шарик — собака dog(tuzik). % кошки cat(pushok). cat(druzgok). % хомячки hamster(pit). % мужчины man(bill). man(george). man(barak). man(platon). man(sokrat). % женщины woman(ann). woman(kate). woman(pam). % ныне покойные dead(sharik). dead(platon). dead(sokrat). % возраст age(sharik, 18). % возраст Шарика — 18 лет age(tuzik, 10). age(pushok, 5). age(druzhok, 2). age(bill, 62). age(george, 62). age(barak, 47). age(sokrat, 70). age(platon, 80). age(ann, 20). age(kate, 25). age(pam, 30). % животные animal(X) :- dog(X); % это либо собака cat(X); % либо кошка hamster(X). % либо хомячок % Читается как: X — животное, если X — собака, либо Х — кошка, либо Х — хомяк. % люди human(X) :- man(X); % либо мужчина woman(X). % либо женщина % живые (или жившие) существа living(X) :- animal(X); human(X). % живые (в данный момент) существа alive(X) :- living(X), + dead(X). % старый old(X) :- ( animal(X) -> age(X, Age), Age >= 10 % считаем, что животные старше 10 лет — старые ; human(X), age(X, Age), Age >= 60 % считаем, что люди старше 60 лет — старые ), + dead(X). % старые, но при этом — живые % молодой — значит — живой и не старый young(X) :- alive(X), + old(X).
Традиционно разберём, что есть что в этой программе. Внимательно наблюдайте, как формируются простые определения, а на их основе формируются более сложные определения.
Cначала дадим собакам, кошкам, хомячка, мужчинам и женщинам имена. Для простоты будем использовать имена, написанные латинскими буквами. Обратите внимание, что имена начинаются со строчных (маленьких букв).
% собаки dog(sharik). % дословно означает, что Шарик — собака dog(tuzik). % кошки cat(pushok). cat(druzgok). % хомячки hamster(pit). % мужчины man(bill). man(george). man(barak). man(platon). man(sokrat). % женщины woman(ann). woman(kate). woman(pam).
Затем укажем имена тех, кто уже покинул этот мир (dead):
dead(sharik). dead(platon). dead(sokrat).
Далее укажем для всех их возраст:
age(sharik, 18). % возраст Шарика — 18 лет age(tuzik, 10). age(pushok, 5). age(druzhok, 2). age(bill, 62). age(george, 62). age(barak, 47). age(sokrat, 70). age(platon, 80). age(ann, 20). age(kate, 25). age(pam, 30).
Затем определим, кого считать животным.
Это либо собака, либо кошка, либо хомячок. Как видите, здесь уже появилась первая переменная Х, которая пишется с прописной (заглавной) буквы. Переменная Х просто определяет какое-то имя животного. Это имя будет конкретизировано, то есть переменной X будет присвоено какое-то значение, когда начнётся выполнение запроса и будет выполнено заданное условие запроса. Оператор читается как: X — животное, если X — собака, либо Х — кошка, либо Х — хомяк.
animal(X) :- dog(X); cat(X); hamster(X).
Теперь определим, кого считать людьми. Тут проще. Это могут быть или мужчины, или женщины.
human(X) :- man(X); % либо мужчина woman(X). % либо женщина
Теперь определим, кто является живым существом вообще (living). Очевидно, что это могут быть животные и люди. Кто не в курсе… Человек это тоже живое существо 🙂
living(X) :- animal(X); human(X).
Теперь определим, кто является живым в данный момент существом (alive). Очевидно, что это живое существо вообще (living), но не считающееся умершим (dead):
Помним, что запятая в операторе является логическим оператором И. То есть, чтобы всё определение было TRUE («правда»), необходимо, чтобы обе части оператора (до запятой и после запятой) были тоже TRUE. То есть кто-то, имеющий имя Х, будет считаться живым, только в том случае, если он является живым существом И он не умер.
alive(X) :- living(X), + dead(X).
А сейчас определим, кого считать пожилым живым существом (old). Тут немного посложнее. Будем считаем, что животные старше 10 лет или люди старше 60 лет — пожилые (old). И они еще не умерли (dead).
Помним, что точка с запятой в операторе является логическим оператором ИЛИ. То есть, чтобы всё определение было TRUE («правда»), необходимо, чтобы одна из двух частей оператора (до запятой и после точки с запятой) или сразу обе, были тоже TRUE. То есть кто-то, имеющий имя Х и возраст Age будет считаться пожилым (old), только в том случае, если он является животным (animal) И его возраст 10 и более ( >= ) лет. ИЛИ это человек (human) с именем X и возрастом Age 60 и более лет.
old(X) :- ( animal(X) -> age(X, Age), Age >= 10 % считаем, что животные старше 10 лет — пожилые ; human(X), age(X, Age), Age >= 60 % считаем, что люди старше 60 лет — пожилые ), + dead(X). % старые, но при этом — живые
И, наконец, молодоё живое существо — это существо, которое живо и не является пожилым.
young(X) :- alive(X), + old(X).% молодой — значит — живой и не старый
Теперь можно ввести определённые запросы. Начнём с простого. Попытаемся определить, является ли Ann (в запросе — ann) человеком?
Система ответила «true», то есть, да, ann — человек, так как у нас в программе есть оператор woman(ann) и выполняется одна из частей оператора human(X) :- man(X); woman(X). То есть, выполняя запрос система делает подстановку human(X) :- woman(X) и затем найдя оператор woman(ann), определяет имя Х как ann. В итоге система определяет итоговый оператор human(ann) :- woman(ann). как логичный и выводит на консоль true (правда).
Далее выясним, является ли tuzik человеком?
?- human(tuzik). false.
Естественно, нет — false. В данном случае система выполняет похожие операции. Сначала выполняет оператор human(X) :- man(X); woman(X). Но tuzik в программе определён как животное dog(tuzik) и потому этот оператор выдаёт false, так как dog нет в правой части оператора.
Там только man и woman.
Теперь определим, кто же вообще является человеком?
?- human(Who). Кто человек? Who = bill ;
Нажимая на «пробел» получим остальные имена.
Сразу весь список людей можно получить таким способом:
?- bagof(H, human(H), Humans). Humans = [bill, george, barak, platon, sokrat, ann, kate, pam].
Попробуем узнать, жив ли Сократ? Разберём этот момент подробнее. Некоторые технические моменты сознательно упростим для лучшего понимания. И если вы сможете разобраться в этих деталях, то вам лучше станет понятна логика Пролога.
Выполняя запрос alive(sokrat). (Жив ли Сократ?), система использует оператор alive(X) :- living(X), + dead(X). Здесь в правой части оператора стоит запятая, потому оба условия в правой части должны быть true, то есть выполняться, чтобы условие alive(X) — было тоже true. То есть система пытается подставить имя sokrat вместо переменной X в оба условия правой части.
Сначала система проверяет оператор living(sokrat). Для этого проверяется составной оператор: living(X) :- animal(X); human(X).
Опять вместо X подставляется sokrat: living(sokrat) :- animal(sokrat); human(sokrat).
Здесь стоит точка с запятой, потому может выполниться только одно из условий в правой части. В данном случае рассмотрим вариант с human, хотя система будет проверять аналогично и вариант с animal.
human(sokrat) — тоже составной оператор: human(X) :- man(X); woman(X). После подстановки X = sokrat он будет иметь вид human(sokrat) :- man(sokrat); woman(sokrat). Опять видим точку с запятой, то есть может выполниться только одно из условий в правой части.
Так как у нас в программе есть оператор man(sokrat), то в итоге оператор human(X) выдаст true, и соответственно оператор living(sokrat) :- animal(sokrat); human(sokrat). тоже выдаст true.
Вернёмся к оператору alive(X) :- living(X), + dead(X). Сейчас система определила, что первое условие в правой части living(X) — есть true, так как living(sokrat) — true.
Далее система проверит второе условие в правой части + dead(X). Это условие говорит о том, что человек будет считаться живым, если он НЕ умер. Но у нас есть в программе оператор dead(sokrat)., который объявляет, что sokrat — умер.
Если sokrat умер, то условие + dead(sokrat). ( НЕ умер (sokrat) ) — false (ложь).
В итоге мы получаем, что в операторе alive(X) :- living(X), + dead(X). в правой части условие living(sokrat) — true (правда), а условие + dead(sokrat). — false (ложь). Так как эти части разделены запятой, то для истинности всего оператора alive(sokrat) эти ОБЕ части должны быть true. В случае с sokrat это не так, потому весь оператор alive(X) :- living(X), + dead(X).
в случае sokrat получает значение false, которое система выводит как ответ на запрос.
?- alive(sokrat) false.
Аналогично можно узнать, жив ли pit. Так как pit нет в списке умерших, то система выводит true, то есть piy жив.
% перечислить молодых % ?- young(Y). % Y = pushok ;
% перечислить молодых мужчин % ?- young(H), man(H). % H = barak ; % false.
% показать все пары живых существ, где одно старше другого в 2 раза % ?- living(X), living(Y), age(X, AgeX), age(Y, AgeY), AgeX =:= 2 * AgeY. % X = tuzik, % Y = pushok, % AgeX = 10, % AgeY = 5 ; % X = ann, % Y = tuzik, % AgeX = 20, % AgeY = 10 ; % false.
Источник: verim.org