4. Стандартные предикаты

4.1. Ввод/вывод
4.2. Управление экраном и оконная система
4.3. Обработка строк
4.4. Преобразование типов
4.5. Работа с базой данных
4.6. Управляющие предикаты
4.7. Прочие стандартные предикаты
4.8. Арифметические и логические предикаты..
Приложение

Одной из основных причин, которые помогли Прологу стать "реальным" языком программирования, было введение в язык элементов, лежащих за пределами чистой логики. В Турбо-Прологе такие элементы реализованы как стандартные (встроенные) предикаты.
Большинство стандартных предикатов выполняет несколько функций в зависимости от состояния параметров, входящих в предикат. В одном случае заранее определен какой-либо один параметр, в другом случае известны другие параметры, иногда к моменту обращения могут быть известны все параметры. Известные параметры предиката называются входными, неизвестные – выходными. Совокупность входных и выходных параметров определяет работу предиката. Эта совокупность называется поточным шаблоном. Если предикат будет вызываться с двумя аргументами, имеется четыре варианта поточного шаблона:
            (i,i)            (i,o)            (o,i)            (o,o),
где i – входной параметр, о – выходной параметр.  Однако не для каждого предиката все возможные варианты поточного шаблона имеют смысл.
Hиже приводятся некоторые наиболее часто употребляемые стандартные предикаты, сгруппированные в отдельные классы по их функциональному назначению. Более полный список стандартных предикатов можно найти в [3].

4.1. Ввод/вывод

readln(StringVariable)
(string) – (o)
Считывает строку с текущего устройства ввода и связывает ее с заданной переменной StringVariable. Обычно чтение производится с клавиатуры. В качестве конца строки используется символ возврата каретки. Readln считывает до 150 символов в строке при вводе с клавиатуры и до 64К при вводе с других устройств.

readint(IntgVariable)
(integer) – (o)
Читает целое число с текущего устройства ввода и связывает его с заданной переменной.

readreal(RealVariable)
(real) – (o)
Читает действительное число с текущего устройства чтения и связывает его с заданной переменной RealVariable. Обычно чтение производится с клавиатуры.

readchar(CharVariable)
(char) – (o)
Читает символ с текущего устройства ввода и связывает его с заданной переменной CharVariable. В отличие от inkey устанавливает режим ожидания ввода.

inkey(CharVariable)
(char) – (o)
Читает символ со стандартного устройства ввода. В отличие от предиката readchar выполнение программы не прерывается. Поэтому inkey применяют главным образом для организации циклов ожидания.

keypressed
В
ыполняется успешно, если нажата некоторая клавиша. В отличие от предиката inkey с помощью keypressed можно установить, нажата ли клавиша, не читая при этом введенный с клавиатуры символ.

write( Variable|Constant * )
Запись заданных значений переменных и констант в заданное активное окно на текущем устройстве вывода.

nl
В
ызывает возврат каретки и перевод строки.

4.2. Управление экраном и оконная система

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

Фон

 Передний план

Черный                               0

Черный          0

Голубой                            16

Голубой         1

Зеленый                            32

Зеленый         2

Бирюзовый                       48

Бирюзовый     3

Красный                           64

Красный          4

Алый                                 80

Алый                5

Коричневый                     96

Коричневый      6

Белый                             112

Белый                7

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

makewindow(WindowNo, ScrAtt, FrameAtt, Framestr, Row, Column, Height, Width)
(integer,integer,integer,string,integer,integer,integer,integer)
- (i,i,i,i,i,i,i,i) (o,o,o,o,o,o,o,o)
Определяет для (i,i,i,i,i,i,i,i) область экрана в качестве окна. Каждое окно задается номером WindowNo. ScrAtt задает значение атрибута для всех позиций описываемого окна. Если FrameAtt не равно 0, окно берется в рамку и верхняя граница включает текст Framestr. Позиция левого верхнего угла окна задается параметрами Row и Col. Параметры Height и Width определяют соответственно высоту и ширину окна, которые должны быть совместимыми с размерами экрана. В случае (о,о,о,о,о,о,о) связывает характеристики текущего окна с выходными параметрами.

shiftwindow(WindowNo)                            
(integer) – (i) (o)
Активизирует (i) окно с номером WindowNo. Окно должно быть создано заранее. Связывает (o) c параметром "номер текущего окна".

removewindow
У
даляет текущее активное окно.

clearwindow
О
чищает текущее активное окно.

cursor(Row,Column)
(integer,integer) – (i,i) (o,o)
Для (i,i) помещает курсор в позицию с координатами (Row,Column) или присваивает переменным Row и Column значения текущих координат  курсора при (o,o).

4.3. Обработка строк

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

frontchar(String,FrontChar,RestString)
(string,char,string) – (i,o,o) (i,i,o) (i,o,i) (i,i,i) (o,i,i)
Разделяет заданную строку String согласно поточному шаблону на две части: первый символ FrontChar и оставшаяся часть строки RestString.

fronttoken(String,Token,RestString)
(string,string,string) – (i,o,o) (i,i,o)(i,o,i) (i,i,i) (o,i,i)
Разделяет строку, заданную параметром String, на лексему Token и остаток RestString согласно поточному шаблону. (Лексема – это последовательность символов, имеющих смысл. Она определяется либо как имя в соответствии с синтаксисом Турбо-Пролога, либо как строчное представление числа, при этом знак возвращается отдельно, либо как отдельный символ.)

frontstr(Lenght,Inpstring,StartString,RestString)
(integer,string,string,string) – (i,i,o,o)
Разделяет строку Inpstring на две части. StartString будет иметь длину Lenght первых символов исходной строки, RestString представляет собой остаток строки   InpString.

concat(String1,String2,String3)
(string,string,string) – (i,i,o) (i,o,i) (o,i,i) (i,i,i)
Слияние строк, согласно поточному шаблону, по формуле: String3 = String1 + String2.

str_len(String,Length)
(string,integer) – (i,i) (i,o) (o,i)
Определяет длину Length строки String.

isname(StringParam)
(string) – (i)
Завершается успешно, если StringParam есть имя, удовлетворяющее синтаксису Пролога.

4.4. Преобразование типов

Стандартные предикаты данной группы служат для преобразования символов с десятичным кодом ASCII, строк с отдельным символом, строк с целыми и действительными числами, а также строчных букв латинского алфавита с соответствующими прописными буквами.
char_int(CharParam,IntgParam)
(char,integer) – (i,o) (o,i) (i,i)
Преобразует символ в код ASCII, согласно поточному шаблону.
str_int(StringParam,IntgParam)
(string,integer) – (i,o
) (o,i) (i,i)
Строка, представляющая целое десятичное число, преобразуется в это число.
str_char(StringParam,CharParam)
(string,char) – (i,o) (o,i) (i,i)
Один знак как строка преобразуетс в символ.
str_real(StringParam,RealParam)
(string,real) – (i,o) (o,i) (i,i)
Строка, представляющая десятичное число, преобразуется в это число.

4.5. Работа с базой данных

consult(DosFileName)
(string) – (i)
Добавляет текстовый файл с именем DosFileName к текущей базе данных. Текстовый файл может быть, например, создан в результате выполнения предиката save. Этот файл содержит факты, которые должны быть описаны в разделе DbaseDom. Выполнение предиката не будет успешным, если в файле имеются синтаксические ошибки.

save(DosFileName)
(string) – (i)
Записывает динамическую базу данных на диск в текстовый файл с именем DosFileName. После этого файл можно снова загрузить в оперативную память, используя предикат consult. Для хранения каждого факта используется отдельная строка. Текстовый файл, представляющий собой всю базу данных, можно просмотреть и изменить, используя редактор Пролога.

asserta( Term )
(DbaseDom) – (i)
Заносит факт Term в базу данных перед другими фактами. Факт должен быть термом, принадлежащим области определения DbaseDom.

assertz( Term )
(DbaseDom) – (i)
Заносит факт Term в конец базы данных. Факт должен быть термом, принадлежащим области определения DbaseDom.

retract( Term )
(DbaseDom) –  (_)
Удаляет первый факт из базы данных, который соответствует заданному факту Term.

retractall(Term)
(InternalDatabaseDomain) – (_)
Очищает всю базу данных.

4.6. Управляющие предикаты

exit
В
ыполняет немедленный выход из программы.

fail
В
ынуждает завершиться предикат ложно и, следовательно, возвратиться к предыдущей точке разветвления (backtracking).

true
Значение предиката всегда истинно.

!
Отсечение (прекращение перебора между головой дизъюнкта и данным знаком).

4.7. Прочие стандартные предикаты

random(RealVariable)
(real) – (o)
Равномерное псевдослучайное число в диапазоне от 0 до 1.

random(MaxValue,RandomInt)
(integer,integer) – (i,o)
Равномерное псевдослучайное целое число RandomInt в диапазоне от 0 до MaxValue.

findall( Variable, Atom, ListVariable )
В списке ListVariable возвращаются все решения для переменной Variable предиката Atom.

not( Atom )
Выполняется успешно, если заданный Atom представляет собой цель, которая не достигается.

free( Variable )
Выполняется успешно, если Variable не является конкретизированной переменной.

bound( Variable )
Выполняется успешно, если Variable является конкретизированной переменной.

4.8. Арифметические и логические предикаты

В арифметических операциях могут участвовать операнды (числа и переменные), арифметические операции + (сложение), – (вычитание), * (умножение), / (деление), mod (деление по модулю), div (целочисленное деление), скобки.
Приоритет выполнения операций представлен числами:            


     + , –                 

    1

    * , /                

    2

    div ,mod        

    3

    – ,+ (унарные)

    4

Логические операторы:


>

Больше

 <

Меньше

 =

Равно

 >=

Больше или равно

 <=

Меньше или равно

 < >

Не равно

Арифметические функции:      


        sin(Х)

Синус, угол в радианах

        cos(Х)

Косинус, угол в радианах

        tan(Х)

Тангенс, угол в радианах

        arctan(Х)

Арктангенс

        ln(Х)

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

        log(Х)

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

        abs(X)

Модуль аргумента

        exp(Х)

Экспонента

        sqrt(Х)

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

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

Приложение

Приложение 1. Примерные варианты лабораторных заданий

1. Родословное дерево
1. Составить родословную своей семьи, использовав 10-12 отношений родитель. Определить предикат пол  для каждого члена семьи.
2. Определить предикаты  мать, отец, дядя, тетя, кузен, дед, внук.
3. Определить рекурсивный предикат  предок.
5. Определить предикат  найти_тетю(Х) , выдающий информацию о наличии  (отсутствии) тети у личности  Х. Определить предикаты о наличии прочих родственников у личности  Х.
6. Определить предикат, дающий список всех родственников личности  Х. Переменную  Х ввести.
2. Вопросно-ответная система
Вариант 1. Что делать, если Вы заболели?
Если у Вас грипп и Вы находитесь в уязвимом возрасте, то
вызовите врача.
Если у Вас острый фарингит, то вызовите врача.
Если у Вас простуда, то примите аспирин и ложитесь в постель.
Если у Вас грипп и вы не находитесь в уязвимом возрасте, то
примите анальгин и ложитесь в постель.
Если у Вас лихорадка и болят мышцы, то это грипп.
Если у Вас насморк, мышечные боли и нет лихорадки, то это
простуда.
Если у Вас в горле нарывы и есть лихорадка, то это острый
фарингит.
Если Вам меньше 8 или больше 60 лет, то Вы находитесь в
уязвимом возрасте.

Вариант 2. Продажа бухгалтерских программ.
1. Если класс бухгалтерские программы и форма конфигурации системы должна быть жесткой, то лучше всего для вас подходит бухгалтерская программа "1С версия 6.0".
2. Если класс бухгалтерские программы и форма конфигурирования системы должна быть лояльной и программа разработана под оболочку DOS, то лучше всего подходит система бухгалтерских программ "Бест".
3. Если класс бухгалтерские программы и форма конфигурирования системы должна быть лояльной и программа разработана по оболочку Windows и программа одноуровневая, то лучше всего вам подходит бухгалтерская программа "Инфо бухгалтер".
4. Если класс бухгалтерские программы и форма конфигурирования системы должна быть лояльной и программа разработана по оболочку Windows и программа не одноуровневая, то лучше всего вам подходит бухгалтерская программа "Турбо бухгалтер".
5. Если тип "складские программы" и форма конфигурации системы должна быть жесткой, то лучше всего для вас подходит складская программа "Фолио".
6. Если тип "складские программы" и форма конфигурации системы должна быть лояльной, то лучше всего для вас подходит программа "1С склад версия 7.5".

3. Работа со списками
Вариант 1.
В спортивных соревнованиях результат спортсмена оценивается информационной единицей вида:
оценка(<фамилия>, <спортивный разряд>, <список оценок>)
Чтобы выставить оценку спортсмену, надо из списка оценок удалить одну  минимальную, одну максимальную, а для оставшихся оценок найти среднюю  арифметическую.
1. Записать правило "оценка _спортсмена".
2. Определить предикат "мастер", если средняя оценка спортсмена больше 5.5 и спортсмен имеет первый разряд.
3. Определить предикат "аутсайдер", если среди оценок есть минимальная. Минимальную оценку ввести.

Вариант 2.
Продуктовая фирма производит готовые салаты. Имеется информация вида

салат( <название салата>, <список ингредиентов> ).
продукты_экзотические( <список экзотических продуктов> ).
морепродукты( <список морепродуктов> ).

1. Определить предикат "сложный_салат", если число ингредиентов больше 5.
2. Определить предикат "витаминный_салат", если в состав салата входит сырая морковь или овсяные хлопья.
3. Определить предикат "морской_салат", если в состав входят морепродукты.
4. Определить предикат "экзотический_салат", если в состав входят, по крайней мере, два экзотических продукта.
4. Поиск пути на графе.
Вариант 1.
Задана система двусторонних дорог, причем для любой пары можно указать соединяющий их путь. Найти такой город, для которого сумма расстояний до остальных городов минимальна.
Вариант 2.
Задана система двусторонних дорог. N-периферией называется множество городов, расстояние от которых до выделенного города (столицы) больше N. Определить N-периферию для заданного города G (среди всех возможных расстояний от столицы до заданного города следует выбирать минимальное).
5. Разработайте прототип классификационной экспертной системы
З
а основу взять одну из программ классификации. Дополните программу механизмом объяснений, возможно, обработки негативных признаков, загрузки базы данных, множественных значений лингвистических переменных, просмотра правил. Выберите в качестве предметной области одну из предложенных тем:
а) приобретение автомобиля (в зависимости от марки машины, стоимости, места сборки и т.д.);
б) выбор подарка в магазине (мужчине, женщине, возраст, стоимость и т.д.);
в) выбор книги для чтения в библиотеке;
г) где провести каникулы (зимой, летом, дом отдыха, турбаза, развлечения);

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

     John makes good coffee for his friends.
     Starkid paints his spaceship every year.
     I usually get up at
seven o’clock.
     First I bought new space shoes.
     The sport shop is opposite the hotel.

2.5. Примеры

 Пример №1:

 

/* Copyright (c) 1986, '92 by Prolog Development Center */

domains

   my_dom = f(string)

   db_selector = my_dba

 

predicates

   write_dba(integer)

   read_dba

   rd(Ref)

   count_dba(integer)

   count(Ref, integer, integer)

   replace_dba

   replace(Ref)

   double_dba

   double(Ref)

   half_dba

   half(Ref)

   mixture

 

clauses

   write_dba(0) :- !.

   write_dba(N) :-

      chain_inserta(my_dba, my_chain, my_dom, f("Prolog system"), _),

      chain_insertz(my_dba, my_chain, my_dom, f("Prolog Compiler"), _),

      N1=N-1,

      write_dba(N1).

 

   read_dba :-

      db_chains(my_dba, Chain),

      chain_terms(my_dba, Chain, my_dom, Term, Ref),

      write("\nRef=", Ref, ", Term=", Term),

      fail.

   read_dba :-

      db_chains(my_dba, Chain),

      chain_first(my_dba, Chain, Ref),

      rd(Ref),

      fail.

   read_dba.

 

   rd(Ref) :-

      ref_term(my_dba, my_dom, Ref, Term), nl, write(Term), fail.

   rd(Ref) :-

      chain_next(my_dba, Ref, Next), !, rd(Next).

   rd(_).

 

   replace_dba :-

      chain_first(my_dba, my_chain, Ref),

      replace(Ref).

 

   replace(Ref) :-

      term_replace(my_dba, my_dom, Ref, f("Prolog Toolbox")),

      chain_next(my_dba, Ref, NN),

      chain_next(my_dba, NN, Next), !,

      replace(Next).

   replace(_).

 

   half_dba :-

      chain_last(my_dba, my_chain, Ref),

      half(Ref).

 

   half(Ref) :-

      chain_prev(my_dba, Ref, PP),

      chain_prev(my_dba, PP, Prev), !,

      term_delete(my_dba, my_chain, Ref),

      half(Prev).

   half(_).

 

   double_dba :-

      chain_first(my_dba, my_chain, Ref),

      double(Ref).

 

   double(Ref) :-

      chain_next(my_dba, Ref, Next), !,

      chain_insertafter(my_dba, my_chain, my_dom, Ref,f("Programmers Guide"), _),

      double(Next).

   double(_).

 

   count_dba(N) :-

      chain_first(my_dba, my_chain, Ref),

      count(Ref, 1, N).

 

   count(Ref, N, N2) :-

      chain_next(my_dba, Ref, Next), !,

      N1=N+1,

      count(Next, N1, N2).

   count(_, N, N).

 

   mixture :-

      write("\nReplace every second term:"),

      replace_dba,

      write("\nDouble the number of terms:"),

      double_dba,

      write("\nErase every second term:"),

      half_dba,

      write("\nUse ref_term for all terms:"),

      read_dba,

      count_dba(N),

      write("\nThere are now ", N, " terms in the database"),

      db_statistics(my_dba, NoOfTerms, MemSize, DbaSize, FreSize),

      writef("\nNoOfTerms=%, MemSize=%, DbaSize=%, FreeSize=%", NoOfTerms, MemSize,DbaSize,FreSize).

 

goal

   write("\n\n\n\tTEST OF DATABASE SYSTEM\n\t***********************\n\n"),

   time(H1, M1, S1, D1),

   db_create(my_dba, "dd.dat", in_memory),

   write("\n\nWrite some terms in the database:"),

   write_dba(50),

   read_dba,

   mixture,

 

   write("\n\n\nCopy to file"),

   db_copy(my_dba, "dd.dat", in_file),

   db_close(my_dba),  db_delete("dd.dat", in_memory),

   db_open(my_dba, "dd.dat", in_file),

   mixture,

   db_close(my_dba),

 

   write("\n\n\nOpen the database on file"),

   db_open(my_dba, "dd.dat", in_file),

   mixture,

   db_close(my_dba),

 

   time(H2, M2, S2, D2),

   Time = (D2-D1)+100.0*((S2-S1)+60.0*((M2-M1)+ 60.0*(H2-H1))),

   write("\n\nTime = ", Time, "/100 Sec" ), nl.