- •Введение
- •1.Основные элементы языка Пролог. Структура программы на языке Пролог.
- •2. Структуры. Состав логических операций в Прологе. Решение логической задачи в tp.
- •3. Использование рекурсии. Построение программ с использованием основных структур данных Пролога - списков.
- •1.Принадлежность.
- •2.Сцепление.
- •4. Использование механизма отсечения для оптимизации поиска решения в программах на Прологе.
- •5. Управление стратегией вывода в экспертных системах с помощью обратной цепочки рассуждений.
- •6. Управление стратегией вывода в экспертных системах с помощью прямой цепочки рассуждений.
- •7.Управление стратегией выбора в экспертных системах с помощью эвристик.
- •8. Получение вывода экспертными системами в условиях неопределённости.
- •9. Организация в экспертных системах ответов на вопросы “Почему” и “Как”.
- •Рекомендуемая литература.
1.Принадлежность.
Предикат member(X,Y) означает, что X принадлежит списку Y. Для определения необходимо рассмотреть два случая: X - есть голова списка; X - содержится в хвосте списка. Получаем:
member(X,[X|_]).
member(X,[_|Tail]): - member(X,Tail).
2.Сцепление.
Предикат append(L1,L2,L3) означает, что L3=L1+L2.Для определения необходимо рассмотреть два случая: если первый аргумент пуст, то второй и третий представляют собой один и тот же список; если первый аргумент не пуст, то окончательный список состоит из головы L1, остатка L1 и списка L2. Получаем:
append([],L2,L2).
append([X|Tail],L2,[X|Tail3]): - append(Tail1,L2,Tail3).
3.Добавление. Наиболее простой способ добавить элемент в список - это вставить его в самое начало так, что бы он стал головой. Получаем:
add(X,L,[X|L]).
4.Удаление. Предикат delete(X,L1,L2) означает, что элемент Х удаляется из списка L1 и получается список L2, т.е. L1=X+L2. Для определения необходимо рассмотреть два случая: Х есть голова списка; Х - в хвосте. Получаем:
delete(X,[X|Tail1],Tail1).
delete(X,[Y|Tail1],[Y|Tail2]):-
delete(X,Tail1,Tail2).
Рассмотрим примеры, демонстрирующие работу со списками.
1.Предикат "принадлежит" представляет собой наименьший полезный пример рекурсивного предиката. При доказательстве предиката member(d,[a,b,c,d,e,f,g]) будет ответ "истино". При доказательстве предиката member(2,[3,a,4,f]) - "ложно".
Каждый раз, когда при согласовании member с базой данных выбирается второе утверждение этого предиката, Пролог рассматривает рекурсивное обращение к предикату member как попытку найти соответствие для некоторой новой его "копии". Это предотвращает путаницу переменных, соответствующих одному употреблению утверждения и соответствующих другому употреблению этого утверждения.
2.Предикат "сцепление". Возможны следующие варианты использования этого предиката.
а) Для разбиения:
? - append(L1,L2,[a,b,c]);
б)Для поиска в списке комбинации элементов, отвечающей некоторому условию, задаваемому в виде образца:
? - append(X,[d|Y],[a,b,c,d,...z]) .
X=[a,b,c]; Y= [e,…,z].
? - append(_,[Month1,"май",Month2|_],
["январь,"февраль",...,"декабрь"]);
Month1= “апрель”; Month2= “июнь”. .
в) Для удаления из списка элементов:
? - L1=[a,b,z,z,c,z,z,z,d,e],
append(L2,[z,z,z|_],L1).
Имеем результат:
L1=[a,b,z,z,c,z,z,z,d,e]
L2=[a,b,z,z,c];
г) Для определения предиката "принадлежит":
member(X,L): - append(_,[X|_],L).
/* X принадлежит L, если список L можно разбить на два списка таким образом, чтобы элемент Х являлся головой второго из них.*/
д) Для определентия предиката "выделение подсписка":
select_list(S,L): -
append(L1,L2,L)
append(S,L3,L2)
/* S - является подсписком L, если L можно разбить на два списка L1 и L2 и L2 можно разбить на два списка S и L3.*/
Например, для цели:
? - select_list(S,[a,b,c])
имеем результат:
S=[];S=[a];S=[a,b];S=[a,b,c];S=[b];...
3.Предикат "удалить". Возможны следующие варианты использования предиката.
а) Для удаления лишь одного вхождения Х, при этом он оставляет остальные в неприкосновенности. Чтобы удалить все, необходимо использовать возврат:
? - delete(a,[a,b,a,a],L).
Имеем результат:
L=[b,a,a]; L=[a,b,a]; L=[a,b,a].
б) Для добавления элементов в список, путем вставления их в произвольные места: ? - delete(a,L,[1,2,3]).
Имеем результат:
L=[a,1,2,3]; L=[1,a,2,3]; L=[1,2,a,3]; L=[1,2,3,a].
в) Можно определить "вставить" через "удалить":
insert(X,L,Big_L): - delete(X,Big_L,L).
г) Можно определить "принадлежит" через "удалить":
member(X,L): - delete(X,L,_).
Рассмотрим примеры предикатов, используемых для обработки списков.
1.Определить количество элементов Y входящих в список X. Для подсчета определим предикат listlen(X,Y).
listlen([],0).
listlen([_|Tail],N): - listlen(Tail,X),N=X+1 .
Для цели: listlen([a,b,c],Y) имеем ответ: Y=3.
2. Определить порядковый номер N элемента Е списка L. Для подсчета определим предикат index(L,N,E ):
index([X|_],1,X): - !.
index([_|Tail],N,X): - N>1,N1=N-1,index(Tail,N1,X).
3. Вывести последовательно все элементы списка, по одному в каждой строке. Для решения этой задачи определим следующие правила:
write_list([]).
write_list([H/Tail]): - write(H),nl,write_list(Tail).
Первое предложение является граничным условием, т.е. оно говорит о том, что необходимо прекратить выход, если список пуст. Второе задает вывод головы списка, переход к новой сроке и рекурсивный вызов предиката, выводящего хвост списка.
4. При работе со списками часто используется встроенный предикат findall. Он имеет следующий вид:
findall(Variable, Goal, List ).
Этот предикат организует список List, состоящий из значений переменной Variable, удовлетворяющих цели Goal.
Пример: Имеется список людей. Требуется определить их средний возраст.
domains
name, address = string
age = integer
list = age*
predicates
person(name, address, age)
sumlist(list, age, integer)
goal
findall(Age, person(_, _, Age), L),
sumlist(L, Sum, N),
Ave = Sum/N,
write("Average =", Ave), nl.
clauses
sumlist([], 0, 0).
sumlist([H|T], Sum, N):- sumlist(T, S1, N1), Sum=H+S1,
N=1+N1.
person("Sherlock Holmes", "22B Baker Street", 42).
person("Pete Spiers", "Apt. 22, 2ist Street", 36).
person("Mary Darrow", "Suite 2, Omega Home", 51).
5. Объекты в списке могут являться списками. При этом все элементы в списке должны принадлежать одному и тому же типу. На Прологе это описывается следующим образом:
domain
objectlist = objects*
objects = symbol*
predicates
member(objects,objectlist).
Упражнения: Реализовать на языке Пролог с использованием списков следующие задачи:
1.Имеется два типа объектов, которые используются для изготовления велосипеда. Это узлы и детали. Узлы состоят из набора деталей. Узел велосипед состоит из деталей: колесо, колесо, рама. Узел колесо состоит из деталей: спица, обод, ступица. Узал рама состоит из деталей: задняя рама, передняя рама. Узел передняя рама состоит из деталей: вилка руль. Узел ступица состоит из деталей: шестерни, ось. Узел ось состоит из деталей: болт гайка. Составить программу, которая для заданного узла перечислит все детали, необходимые для его сборки.
2.Составить программу на Турбо-Прологе, которая в ответ на введённое с терминала предложение (на английском языке) печатает другое предложение, представляющее исходное предложение. Использовать операции преобразования списка. Примерный диалог пользователя с программой выглядит следующим образом:
П.: You are a computer?
М.: I am not a computer.
П.: Do you speak french?
М.: No i speak german.
3.Определить предикат “лин” для “линеаризации” списка путём построения нового списка, не содержащего списков в качестве элементов, но включающего все атомы исходного списка. Например, следующее утверждение должно быть согласовано с базой данных:
лин([a,[b,c]],[[d],[],e]], [a,b,c,d,e]).
4.Составить программу, реализующую основные действия (сложение, вычитание, деление, умножение) над полиномами.