Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ФЛП.doc
Скачиваний:
14
Добавлен:
24.09.2019
Размер:
478.72 Кб
Скачать

Унификация составных объектов

    Составной объект может быть унифицирован с простой переменной или с составным объектом (возможно, содержащим переменные в качестве частей во внутренней структуре), который ему соответствует. Это означает, что составной объект можно использовать для того, чтобы передавать целый набор значений как единый объект, и затем применять унификацию для их разделения. Например:

date("April",14,1960)

сопоставляется с X и присваивает X значение date("April ",14, 1960). Также

date("April",14,1960)

сопоставляется с date(Mo,Da,Yr) и присваивает переменным Mo="April", Da=14 и Yr = 1960.

Использование знака равенства для унификации составных объектов

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

    Фактически, Пролог выполняет операцию присваивания для унификации объектов по разные стороны знака равенства. Это свойство полезно для нахождения значений аргументов составного объекта. Например, программа pro35_1.pro проверяет, совпадают ли фамилии у двух людей, и затем дает второму человеку тот же адрес, что и у первого.

domains

person=person(name,address)

name=name(first,last)

address=addr(street,city,state)

street=street(number,street_name)

city,state,street_name=string

first,last=string

number=integer

goal

P1=person(name(jim,mos), addr(street(5,"1st st"), igo, "CA")),

P1=person(name(_,mos), Address),

P2=person(name(jane,mos), Address),

write("P1=",P1) ,nl,

write("P2=",P2),nl.

    Текст этой программы можно взять здесь.

Использование нескольких значений как единого целого

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

owns(john,book("From Here to Eternity","James Jones")).

в котором утверждается, что у Джона есть книга "From Here to Eternity" (Отсюда в вечность), написанная James Jones (Джеймсом Джонсом). Аналогично можно записать:

owns(john,horse(blacky)).

что означает:

    John owns a horse named blacky.(У Джона есть лошадь Блеки.)

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

book("From Here to Eternity","James Jones")

и

horse(blacky)

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

owns(john,"From Here to Eternity"),

owns(john,blacky).

то нельзя было бы определить, является ли blacky названием книги или именем лошади. С другой стороны, можно использовать первый компонент составного объекта - функтор для распознавания различных объектов. Этот пример использует функторы book и horse для указания разницы между объектами.

    Замечание. Составные объекты состоят из функтора и объектов, принадлежащих этому функтору, например: functor(objectl,object2,..., objectN).

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

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

predicates

phone_list(symbol First, symbol Last, symbol Phone,

symbol Month, integer Day, integer Year)

clauses

phone_list(ed,willis,422_02_08,aug,3,1955).

phone_list(chris,grahm,433_99_06,may,12,1962).

    Обратите внимание, что в факте phone_list шесть аргументов, пять из них могут быть разбиты (рис. 3) на два составных объекта.

Рис.3. Разбивка составных объектов

    Может оказаться более полезным представлять факты так, чтобы они отражали эти составные объекты данных. Вернувшись на шаг назад, видим, что person (лицо) - это отношение, а имя и фамилия - объекты. Также, birthday (день рождения) - это отношение между тремя аргументами: месяцем, днем и годом. В представлении Пролога они могут быть записаны следующим образом:

person(First_name,Last_name)

birthday(Month,Day,Year)

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

domains

name=person(symbol First,symbol Last)

birthday = b_date(symbol Month, integer Day, integer Year)

ph_num = symbol % Phone_number

predicates

phone_list(name, ph_num, birthday)

clauses

phone_list(person(ed,willis),"422-02-08",b_date(aug,3,1955)).

phone_list(person(chris,grahm),"433-99-06",b_date(may,12,1962)).

    В эту программу введены два определения составных доменов. Мы рассмотрим некоторые подробности этих составных структур данных далее, а сейчас остановимся на применении таких составных объектов.

    Предикат phone_list теперь содержит три аргумента, что отличается от шести предыдущем примере. Иногда разбиение данных и составном объекте делает более ясной логику программы и может помочь в обработке данных. А теперь добавим несколько правил в нашу маленькую программу. Допустим, вы хотите создать список людей, у которых день рождения в этом месяце. Ниже приведена программа pro35_2.pro, которая решает эту задачу, используя встроенный предикат date для получения даты из внутреннего календаря компьютера. Предикат date возвращает текущие год, месяц и день из календаря компьютера.

domains

name=person(symbol,symbol) % (первый,последний)

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

ph_num=symbol % телефонный номер

predicates

phone_list(name,ph_num,birthday)

get_months_birthdays()

convert_month(symbol,integer)

check_birthday_month(integer,birthday)

write_person(name)

clauses

get_months_birthdays:-

write("************ This Month's Birthday List ***********+*"),nl,

write(" First name\t\t Last Name\n"),

write("*****************************************************"),nl,

date(_, This_month, _), % получить месяц из системных часов

phone_list(Person, _, Date),

check_birthday_month(This_month, Date),

write_person(Person) ,

fail.

get_months_birthdays:-

write("\n\n Press any key to continue: "),nl,

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,Monthl),

Mon = Monthl.

phone_list(person(ed,willis),"7 67-84 63",b_date(jan, 3,1955)).

phone_list(person(benjamin,thomas),"438-8400",b_date(feb,5,1985)).

phone_list(person(ray,william),"555-5653",b_date(mar,3,1935)).

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

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

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

phone_list(person(anna,friend),"767-8463",b_date(jun, 20,1986)).

phone_list(person(brandy,rae),"555-5653",b_date(jul,16,1981)).

phone_list(person(naomi,friend),"767-2223",b_date(aug,10,1981)).

phone_list(person(christina,lynn),"438-8400",b_date(sep,25,1981)).

phone_list(person(kathy,ann),"438-8400",b_date(oct,20,1952)).

phone_list(person(elizabeth,ann),"555-1212",b_date(nov,9,1984)).

phone_list(person(aaron,friend) ,"767-2223",b_date(nov,15,1987)).

phone_list(person(jennifer,caitlin), "438-8400",b_date(dec,31,1981)).

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).

goal

get_months_birthdays().

    Текст этой программы можно взять здесь.

    Результат работы программы можно посмотреть на рис.4

Рис.4. Результат работы программы pro35_2.pro

    Загрузите и запустите эту программу.

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

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

  3. Использует в предикате get_month__birthdays встроенный предикат date.

  4. Кроме того, программа производит поиск в базе данных и печатает список людей, родившихся в текущем месяце. Сначала ищется первый человек в базе данных. Вызов phone_list (Person,_,Date) помещает имя и фамилию человека в переменную Person, помещая функтор person целиком в Person, а день рождения - в переменную Date.

    Заметим, что необходимы две переменные: одна для хранения полного имени человека, а другая - для хранения дня рождения. Это достигается за счет использования составных объектов.

  1. Ваша программа может теперь передавать день рождения человека просто путем передачи переменной Date. Это происходит в следующей подцели, где программа передает текущий месяц (представленный целым числом) и день рождения в предикат check_birthday_month.

  2. Пролог вызывает предикат check_birthday_month с двумя переменными: первая переменная связана с целым, а вторая - с термом birthday. В заголовке правила, которое определяет check_birthday_month, This_month, сравнивается с переменной Mon. Второй аргумент, Date, сопоставляется с b_date(Month,_,_).

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

  1. Предикат check_birtday_month сначала превращает символ месяца в целое число. После того, как это сделано, Пролог может сравнить значение текущего месяца с месяцем рождения человека. Если это сравнение удачно, подцель check_birthday_month завершается успешно и обработка продолжается. Если сравнение неуспешно (человек родился в другом месяце), Пролог откатывается для поиска другого решения задачи.

  2. Следующая подцель, которую нужно обработать, - write_person. Лицо, данные которого нужно обработать, имеет день рождения в этом месяце, и поэтому в отчет попадают только правильные данные. После распечатки информации предпожение терпит неуспех, что вызывает поиск с возвратом.

  3. Поиск с возвратом всегда возвращается к последнему неудовлетворенному вызову и пытается его удовлетворить. В данной программе последний неудовлетворенный вызов - phone_list. Поэтому программа будет искать другое лицо, которое может быть обработано. Если в базе данных нет больше людей, текущее предложение терпит неуспех, Пролог пытается доказать этот вызов, просматривая базу данных дальше, но т. к. есть еще предложение get_month_birthdays, Пролог пытается доказать его, доказав подцели этого предложения.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]