Скачиваний:
201
Добавлен:
17.06.2016
Размер:
2.69 Mб
Скачать

Рассмотрение нескольких значений как единое целое.

Составные объекты могут рассматриваться в педложениях Пролога, как

единые объекты, что сильно упрощает написание программ. Рассмотрим, нап-

ример факт:

имеет(джон,книга("Отсюда в Вечность","Джеймс Джонс")).

в котором утверждается, что у Джона есть книга "Отсюда в Вечность", напи-

санная Деймсом Джонсом. Аналогично можно записать:

имеет(джон,лошадь(блеки)).

что означает: у Джона есть лошадь Блеки.

Составными объектами в этих двух примерах являются

книга("Отсюда в Вечность","Джеймс Джонс")

и лошадь(блеки)

Если вы вместо этого описали бы два факта :

имеет(джон,"Отсюда в Вечность").

имеет(джон,блеки).

Вы не смогли бы определить, является ли Блеки названием книги или

именем лошади. С другой стороны, вы можете использовать первый компонент

составного объекта - функтор для распознавания различных объектов. Этот

пример использует функторы книга и лошадь для указания разницы между объ-

ектами.

Запомните: Составные объекты состоят из функтора и объектов принад-

лежащих функтору, как показано:

функтор(объект1,объект2, ... ,объектN)

Примеры использования функторов.

Не только аргументы, но также и функторы могут нести полезную инфор-

мацию, если вы определите домен с несколькими альтернативными функторами.

Рассмотрим реальную программную задачу, такую как передвижение курсора.

Вы можете считать что у нее два аргумента: направление и расстояние пе-

редвижения. Вы, конечно правы, но для Пролога эти аргументы могут быть

одним объектом.

Программа CH06EX02.PRO показывает как это сделать. Она использует

встроенный предикат cursor(Row,Column) который служит двум целям: он оп-

ределяет где находится курсор, если его аргументы свободны, и помещает

курсор в заданные ряд и колонку, если аргументы связаны.

/* программа CH06EX02.PRO -использование функтора */

domains

row,column,step = integer

movement = up(step); down(step); left(step); right(step)

predisates

move_cursor(row,column,movement)

clauses

move_cursor(R,C, up(Step) :-

cursor(R,C), R1=R-Step, cursor(R1,C) .

move_cursor(R,C, down(Step) :-

cursor(R,C), R1=R+Step, cursor(R1,C) .

move_cursor(R,C, left(Step) :-

cursor(R,C), C1=C-Step, cursor(R,C1) .

move_cursor(R,C, right(Step) :-

cursor(R,C), C1=C+Step, cursor(R,C1) .

Загрузите программу CH06EX02.PRO , нажмите Alt-R для ее запуска и

затем задайте следующие цели (по одной за раз) по приглашению Goal для

того, чтобы посмотреть, как вызывается move_cursor

move_cursor(4,9,up(2)).

move_cursor(6,12,down(2)).

move_cursor(13,15,left1(2)).

move_cursor(14,8,right(5)).

Вы можете добавить альтернативный функтор для пустого движения. Это

будет эаписано, как move_cursor(R,C, no). Заметьте, что функтор no важен

для представления отсуствия движения, он не требует аргументов.

Пример использования составных объектов.

Другая важная особенность составных объектов это то, что они позво-

ляют легко передавать группы величин, как один аргумент. Рассмотрим слу-

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

данных дни рождения ваших друзей и родственников. Здесь приведена часть

программы, которую вы бы написали:

predicates

phone_list(symbol,symbol,symbol,symbol,integer,integer)

/* имя фамилия телефон месяц день год */

clauses

phone_list(ed,willis,422-0208,aug,3,1955).

phone_list(chris,grahm,433-9906,may,12,1962).

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

пять из них могут быть разбиты на два составных объекта, как здесь:

person birthday

/ \ / | \

FirstName LastName Month Day Year

Может оказаться более полезным представлять факты так, чтобы они от-

ражали эти составные объекты данных. Вернувшись на шаг назад, видно, что

person(лицо) - это отношение, а имя и фамилия - объекты. Также,

birthday(день рождения) - это отношение между тремя аргументами: месяцем,

днем и годом. В представлении Пролога они могут быть записаны:

person(First_name,Last_name)

birthday(Month,Day,Year)

Вы можете теперь переписать свою маленькую базу данных с включением

этих составных объектов как части Вашей базы данных.

domains

name=person(symbol,symbol) /* Имя Фамилия */

birthday=b_date(symbol,integer,integer) /* месяц день год */

ph_num=symbol

predicates

phone_list(name,ph_list,birthday)

clauses

phone_list(person(ed,willis),422-0208,b_date(aug,3,1955)).

phone_list(person(chris,grahm),433-9906,b_date(may,12,1962)).

В эту программу введены два определения составных доменов. Мы расс-

мотрим некоторые подробности этих составных структур данных далее в этой

главе. А сейчас мы сосредоточимся на применении таких составных объектов.

Предикат phone_list теперь содержит три аргумента, что отличается от

шести предыдущих. Иногда разбиение данных в составном объекте проясняет

программу и может помочь в обработке данных.

А теперь добавим несколько правил в вашу маленькую программу. Допус-

тим, вы хотите создать список людей, у которых день рождения в этом меся-

це. Здесь приведена программа, которая решает эту задачу, эта программа

использует встроенный предикат date для получения даты из внутреннего ка-

лендаря компьютера. Предикат date будет описан позднее в главе 6. Сейчас

же необходимо знать, что он возвращает текущие год, месяц и день с кален-

даря компьютера.

/* программа CH06EX03.PRO Телефонная книжка и Дни рождения*/

domains

name=person(symbol,symbol) /* Имя Фамилия */

birthday=b_date(symbol,integer,integer) /* месяц день год */

ph_num=symbol /* номер телефона */

predicates

phone_list(name,ph_list,birthday)

get_months_birthdays

convert_month(symbol,integer)

check_birthday_month(integer,birthday)

write_person(name)

clauses

get_month_birthdays :-

makewindow(1,7,7,"Список родившихся в этом месяце",0,0,25,80),

write("Имя\t Фамилия\n"),

date(_,This_month,_),

phone_list(Person,_,Date),

check_birthday_month(This_month,Date),

write_person(Person),fail.

get_month_birthdays :-

write("\n\n Нажмите пробел"),

readchar(_).

write_person(person(First_name,Last_name)) :-

write(" ",First_name,"\t\t ",Last_name), nl.

check_birthday_month(Mon,b_date(Month,_,_)) :-

convert_month(Month,Month1),

Mon=Month1 .

phone_list(person(ed,willis),422-0208,b_date(aug,3,1955)).

phone_list(person(chris,grahm),433-9906,b_date(may,12,1962)).

phone_list(person(benjamin,thomas),555-4565,b_date(mar,3,1935)).

phone_list(person(ray,william),438-8400,b_date(feb,5,1985)).

phone_list(person(thomas,alfred),767-2223,b_date(apr,29,1951)).

phone_list(person(chris,gram),555-1212,b_date(may,12,1962)).

phone_list(person(dustin,robert),438-8400,b_date(jun,17,1980)).

convert_month(jan,1).

convert_month(feb,2).

convert_month(mar,3).

convert_month(apr,4).

convert_month(may,5).

convert_month(jun,6).

convert_month(jul,7).

convert_month(aug,8).

convert_month(sep,9).

convert_month(oct,10).

convert_month(nov,11).

convert_month(dec,12).

Загрузите и запустите эту программу, а затем введите

get_month_birthdays по приглашению Goal:

Чем помогают составные объекты в этой программе ? Это легко увидеть,

если посмотреть текст программы. Большая часть обработки заключена в пре-

дикате get_month_birthdays.

1. Во-первых, программа использует окно для вывода результата

2. Кроме того, она помещает в окне заголовок, помогающий понять ре-

зультат

3. Далее, программа использует в предикате get_month_birthdays вст-

роенный предикат date

4. Кроме того, программа производит поиск в базе данных и печатает

список людей, родившихся в текущем месяце. Сначала ищется первый че-

ловек в базе данных. Вызов phone_list(Person, _,Date) помещает имя и

фамилию человека в переменную Person, а день рождения в переменную

Date.

Заметьте, что необходима только одна переменная для хранения полного

имени человека, и одна переменная для хранения дня рождения. Это

достигается за счет использования составных объектов.

5. Ваша программа может теперь передавать день рождения человека

просто путем передачи переменной Date. Это происходит в следующей

подцели, где программа передает текущий месяц(представленный целым)

и день рождения в предикат check_birthday_month.

6. Посмотрите внимательно, что при этом происходит. Турбо Пролог вы-

зывает предикат check_birthday_month с двумя переменными: первая пе-

ременная связана с целым, а второй с функтором, плюс три его аргу-

мента. В заголовке правила, которое определяет check_birthday_month,

первый аргумент: This_month сравнивается с переменной Mon. Второй

аргумент, Date сопоставляется с b_date(Month,_,_). Это проходит, так

как это тот же объект данных, что и величина, переданная вами. Так

как все это связано с днем рождения человека, используются анонимные

переменные для даты и года рождения.

7. Предикат check_birtday_month сначала превращает символ месяца в

целое число. После того, как это сделано, Турбо Пролог может срав-

нить значение текущего месяца с месяцем рождения человека. Если это

сравнение удачно, подцель check_birthday_month завершается успешно и

обработка продолжается. Если сравнение неуспешно (человек родился в

другом месяце), Турбо Пролог возвращается для другого решения зада-

чи.

8. Следующая подцель, которую нужно обработать - write_person Лицо,

которое нужно обработать, имеет день рождения в этом месяце, и поэ-

тому в отчет попадают только правильные данные. После распечатки ин-

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

9. Поиск с возвратом всегда возвращается к последнему неопределенно-

му вызову и пытается удоволетворить этот вызов. В данной программе

последний неудоволетворенный вызов - phone_list. И поэтому программа

будет искать другое лицо, которое может быть обработано. Если в базе

данных нет больше людей, текущее предложение терпит неудачу, Турбо

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

ше. Так как есть еще предложение get_month_birthday, Турбо Пролог

пытается доказать этот вызов, доказав подцели этого другого предло-

жения.

Соседние файлы в папке Документация