Операции в Прологе

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

Арифметические операции и математические функции применимы только к объектам из доменов real и integer. Логические операции применяются к предикатам. Операции сравнения могут применяться к объектам любого типа.

Таблица 7.1

Вид операции

Функциональный

предикат

Описание

Арифметические операции и математические функции

X mod Y

Остаток от деления X на Y

X div Y

Частное от деления X на Y

abc(X)

Модуль X

cos(X)

Косинус X

sin(X)

Синус X

tan(X)

Тангенс X

arctan(X)

Арктангенс X

exp(X)

Экспонента X

In (X)

Логарифм натуральный X

log(X)

Логарифм десятичный X

sqrt(X)

Корень квадратный X

+ , *, /

Арифметические действия

Продолжение

Вид операции

Функциональный

предикат

Описание

Логические

операции

not

Отрицание

and

Логическое умножение

or

Логическое сложение

Операции сравнения

<, <=,>,> =, о

Меньше, меньше или равно, больше, больше или равно, не равно

Пример. Написать программу для вычисления значения функции:

predicates

function(real, real, real, real)

start clauses

function(X, Y, Z, F) if X*Y < Z, F = X*X.

function (X, Y, Z, F) if X*Y = Z, F = Y+Z.

function(X, Y, Z, F) if X*Y > Z, F = X*Y-Z.

start

if write ("Введите значения"), nl, write ("X = "),

readreal (X), write ("Y = "), readreal (Y), write ("Z = "),

readreal (Z), function (X, Y, Z, F), write ("Результат f (x, y, z) = ", F), readchar (_).

goal start.

Отметим, что предикат readchar (_) использовался для установки режима ожидания ввода, который до нажатия любой клавиши не меняет содержимого экранной области, что дает пользователю возможность просмотреть полученный результат.

Повторение и рекурсия

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

  • — метод отката после неудачи;
  • — метод отсечения и отката;
  • — правило повтора, определяемое пользователем;
  • — обобщенное рекурсивное правило.

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

Стандартный вид для повторения:

repeat_rule if Последовательностьтермов>, fail.

Встроенный предикат fail организует откат, т. е. в случае невозможности выполнения правила он позволяет вернуться назад и повторно попробовать его реализовать. Это действие осуществляется до тех пор, пока не будут исчерпаны все возможные варианты.

Вид для организации рекурсии:

repeat_rule if Последовательность термов>, repeat_rule.

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

Откат после неудачи. Рассмотрим его на следующем примере. Имеется информация о сотрудниках предприятия следующего состава: фамилия, пол и зарплата. Требуется получить информацию обо всех мужчинах.

domains

name = symbol sex = char plat = real

predicates

employee (name, sex, plat) show_all_man

goal

write ("Мужчины компании"), nl, show_all_man.

clauses

employee ("Сидоров", 'M', 150). employee ("Петров", 'M', 200). employee ("Тихонова", 'Ж', 170).

employee ("Иванов", 'М', 160).

show_all_man if employee (Name, Sex, Plat), Sex = 'M', write (Name, Plat), nl, fail.

Метод отсечения и отката. В некоторых ситуациях необходим доступ только к ограниченному набору данных. Выше описано, как fail осуществляет откат, но для управления выбором необходимо средство управления откатом. Для этого служит предикат cut, вместо которого можно использовать символ «!». Это предикат, вычисление которого всегда завершается успешно, заставляет забывать все указатели отката, установленные во время попыток вычислить текущую цель.

Пример. Задан список детей, необходимо выдавать имена из списка, пока не встретится имя Дарья, в этом случае выдачу следует прервать, domains

person = string predicates

child (person) show_all make_person clauses

child ("Петр").

child ("Василий").

child ("Анастасия").

child ("Константин").

child ("Дарья") .

child ("Артем").

child ("Федор Федорович").

show_all if child (Name), write (Name), nl, make_person (Name), !, fail. make_person (Name) if Name = "Дарья".

goal

show_all.

Правим повтора, определяемое пользователем. Также как и предыдущий метод, он использует откат, но в отличие от него, где откат выполняется только в случае искусственно созданного неуспешного результата, в этом методе откат возможен всегда. Вид правила повтора, определяемого пользователем: repeat.

repeat if repeat.

Первый предикат repeat является фактом, который объявляет этот предикат истинным, он всегда выполняется успешно. Так как имеется еще одно правило для его определения, то указатель отката устанавливается на первый repeat. Второй repeat — это правило, которое использует само себя как компоненту (третий repeat). Второй repeat вызывает третий, этот вызов также выполняется успешно, так как первый repeat всегда истинный, т. е. правило repeat тоже всегда успешно. Предикат repeat вычисляется успешно при каждой новой попытке вызвать его после отката. Таким образом, repeat — это рекурсивное правило, которое всегда выполняется успешно.

Такое правило удобно использовать в качестве компоненты других правил для организации бесконечных циклов.

Пример. Напишем программу «эхо», которая считывает строку и дублирует ее на экране. Работа программы завершается после ввода строки stop:

predicates

repeat

analiz (string)

write_text

do

clauses repeat.

repeat if repeat.

write_text if nl, write ("Введите текст, я его повторю"), nl,

write ("Для завершения работы введите слово stop"), nl, nl.

do if repeat, readln (Name), write (Name), nl, analiz (Name), !.

analiz ("stop") if nl, write ("Сеанс окончен.

До свидания"). analiz (_) if fail, goal

write_text, do.

Правило repeat стоит первым в разделе утверждений программы, но это не обязательно. В правиле do наличие repeat вызывает повторение всех стоящих за ней компонент.

Простая рекурсия. Правило, содержащее само себя в качестве компоненты, называется правилом рекурсии, например:

write_string if write ("Пролог - это хорошо"), nl, write_string.

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

Модернизируем предыдущий пример таким образом, чтобы вывод прекращался после заданного числа сообщений:

predicates

write_string (integer, integer) analiz (integer, integer) clauses

write_string (N, M) if write ("Пролог отличный язык!"),

nl, analiz (N, M), Ns = N+l, write_string (Ns, M).

analiz (N, M) if N = M, write ("Сеанс окончен"), exit.

analiz (N, M) if N < = M, !.

goal

write ("Сколько раз следует повторить фразу?"), readint (М), write_string (1, М).

exit — это стандартный предикат, обеспечивающий выход в операционную систему или среду Турбо Пролога в зависимости от того, откуда была запущена программа на исполнение.

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

<имя правила рекурсии> if <термы>,

<условие выхода>,

<термы>,

<имя правила рекурсии>,

<термы>.

Хотя структура и сложнее, чем в изложенном ранее примере, но принципы остаются неизменными.

Пример. Составить программу для нахождения факториала заданного числа:

predicates

factorial (integer, integer) clauses

factorial (1, 1) if ! .

factorial (Number, Rez) if Next_number =

Number-1,

factorial (Next_number, Ok_Rez),

Rez = Number *

Ok_Rez.

goal

factorial (5, Rez), write ("5! = ", Rez).

 
Посмотреть оригинал
< Пред   СОДЕРЖАНИЕ   ОРИГИНАЛ   След >