- •Введение
- •1. История Пролога
- •2. Синтаксис и семантика Пролог-программ
- •2.1. Объекты данных1
- •2.2. Декларативный смысл Пролог-программ
- •2.3. Основные определения
- •3. Практическое программирование на Прологе
- •3.1. Структура Пролог-программы
- •3.2. Некоторые предопределенные термы
- •3.3. Свободные и связанные переменные
- •3.4. Внутренняя бд Пролога
- •3.5. Обработка условий и организация циклов в Prolog’е
- •3.5.1. Обработка условия
- •3.5.2. Использование предиката типа repeat
- •3.6. Списки в Прологе
- •3.6.1. Примеры списков
- •3.6.2. Разделение списков на голову и хвост
- •3.6.3. Некоторые полезные программы для работы со списками
- •1. Слияние списков.
- •2. Сортировка списков
- •3.7. Ввод и вывод
- •3.7.1. Файловая система
- •Операции с именами файлов
- •Чтение и запись
- •3.8. Строки и функции работы со строками
- •4. Простенькая экспертная система
- •Игрушечная эс «Кто чем увлекается?»
- •5. Базовые понятия и термины Пролога
- •5.1. Объекты
- •5.2. Внутренние дела Пролога
- •5.3. Что такое шаблоны?
- •5.4. Управление поиском
- •Литература
3.6.2. Разделение списков на голову и хвост
Основным приемом работы со списками является представление списков в виде «Головы» (Head) и «Хвоста» (Tail). Для иллюстрации напишем правило для предиката p2 из предыдущего раздела:
clauses
p2([]).
p2([l(I,S)|T]):-
write(I," ",S),nl,
p2(T).
Поиск элемента в списке:
search(H,[H,_]).
search(H,[_,T]):-search(H,T).
Получить сумму числовых элементов списка можно очевидным способом:
sumList([],S).
sumList([H|T],S):-S1=S+H,sumList(T,S1).
А для иллюстрации работы со стеком применим «неочевидный» прием:
predicates
sumlist(integer*,integer)
goal
L=[1,2,3,4],
sumlist(L,S),
write(S) .
clauses
sumlist([],0).
sumlist([H|T],X):-sumlist(T,S),X = S+H.
До тех пор, пока не удовлетворено первое правило, Пролог будет очищать список, сбрасывая «головы» в стек. Затем он присвоит 0 свободной переменной. А далее будет суммировать элементы стека, присваявая значения промежуточной суммы переменной X и возвращать элементы стека в список. (По моему мнению, если уж вы выбрали Пролог, не стоит жертвовать логической ясностью ради «оптимизации»)
Встроенный предикат findall
findall собирает компоненты факта в список.
domains
фам_им_от=ф(symbol,symbol,symbol)
лист_фам_им_от=фам_им_от*
facts - f1
гриб(symbol)
язык_программирования(integer,symbol)
фио(фам_им_от)
predicates
собрать_фио(лист_фам_им_от)
................
goal
consult("famio.txt",f1)
%файл "famio.txt" содержит:
%фио("Фадеев","Фиктор","Петрович")
%фио("Иванов","Иван","Иванович")
...............
%фио("Гимазов","Артур","Олегович")
findall(Гриб,гриб(Гриб),Грибы),
findall(Имя_Языка,язык_программирования(_,Имя_Языка),Список),
собрать_фио(СписокФИО).
clauses
собрать_фио(Список):-findall(ФИО,фио(ФИО),Список).
% Список будет состоять из
[ф("Фадеев","Фиктор","Петрович"),ф("Иванов","Иван","Иванович"),...]
3.6.3. Некоторые полезные программы для работы со списками
1. Слияние списков.
Полагаем, что в базе данных facts содержаться два списка (список1, список2), элементами которых являются целые числа. Требуется список1 присоединить к список2. Пусть
список1 есть [5,6,7], а список2 есть [8,9]
domains
список=integer*
facts - f1
список1(список)
список2(список)
predicates
объединить_списки(список,список,список)
goal
список1(Список1),
список2(Список2),!, % А вдруг БД пуста?!
объединить_списки(Список1,Список2,Список3);!.
clauses
объединить_списки([],L,L).
объединить_списки([H|L1],L2,[H|L3]):-
объединить_списки(L1,L2,L3).
Что будет происходить? Поскольку вначале первый список не пуст, Пролог будет пытаться удовлетворить второе правило, очищая первый список. Элементы первого списка пересылаются в стек в оперативной памяти. Когда первый список окажется пустым, становится возможным третьему списку присвоить второй список, и первое правило окажется истинным:
объединить_списки([],[8,9],[8,9]).
Пролог берется за второе правило, сворачивая рекурсию. Начиная с вершины стека, он присваивает элементы «головам» первого и третьего списков. При этом на каждом шаге левая часть второго правила истинна, происходит рекурсивный вызов и так до тех пор, пока стек не опустеет.