- •Приложение 4-5
- •IV. Версии языка пролог СиПролог Поставщик
- •Синтаксис и встроенные предикаты
- •Директивы
- •Среда для разработки программ
- •Отладчик
- •Отладочные команды
- •Компилятор
- •Запомненные состояния
- •Интерфейс с иными языками программирования
- •Расширения языка
- •Квинтус Пролог Поставщик
- •Синтаксис и встроенные предикаты
- •Директивы
- •Среда разработки программ
- •Отладчик
- •Компилятор
- •Запомненные состояния
- •Система программирования на Прологе фирмы Сайлоджик Поставщик
- •Синтаксис и встроенные предикаты
- •Директивы
- •Среда разработки программ
- •Отладчик
- •Компилятор
- •Запомненные состояния
- •Интерфейс с иными языками программирования
- •Расширения
- •Пролог-2 Поставщик
- •Синтаксис и встроенные предикаты
- •Директивы
- •Среда разработки программ
- •Отладчик
- •Компилятор
- •Запомненные состояния
- •Интерфейс с иными языками программирования
- •Расширения
- •Эрити Пролог Поставщик
- •Синтаксис и встроенные предикаты
- •Среда разработки программ
- •Отладчик
- •Компилятор
- •Запомненные состояния
- •Расширения
- •Унсв Пролог Поставщик
- •Синтаксис и встроенные предикаты
- •Директивы
- •Среда разработки программ
- •Отладчик
- •Компилятор
- •Запомненные состояния
- •Интерфейс с иными языками программирования
- •Турбо Пролог Поставщик
- •Синтаксис и встроенные предикаты
- •Среда разработки программ
- •Отладчик
- •Запомненные состояния
- •Интерфейс с иными языками программирования
- •Расширения
- •V. Ответы к упражнениям Ответы к упражнениям
- •Глава 2
- •Глава 3
- •Глава 5
- •Глава 6
- •Глава 7
Глава 2
1.
| ?-X is 10,Y is X*3.
Х=10
Y=30
| ?-X is 10, Y is X * 3, Y is 300.
нет
При вычислении третьей подцели последнего запроса переменная Y уже будет конкретизирована, поэтому данная подцель равнозначна проверке значения Y. В этом упражнении подчеркивается, что в Прологе отсутствует деструктивное присваивание.
2.
площадь (Основание, Высота, Площадь) : — Площадь is Основание * Высота.
| ?—площадь (10,2, П).
П=20
| ?-площадь (10, В, 20).
арифметическая ошибка
Данная программа не является обратимой.
4. Существует два простых решения. Первое из них по форме соответствует процедуре "длина". Оно леворекурсивно и подсчитывает слова по пути назад от конца списка.
% + + найти_слово (Слово, [Слово | Список], Счетчик) :-
найти_слово (Слово, Список, СубСчетчик),
Счетчик is СубСчетчик + 1.
найти_слово (Слово, [ХСлово | Список], Счетчик) :-
найти_слово (Слово, Список, Счетчик).
найти_слово (_, [ ], 0) .
Второе решение является праворекурсивным. В нем используется дополнительный аргумент, предназначенный для накопления суммы по мере продвижения к концу списка. Когда будет достигнут конец списка, накопленная сумма будет передана четвертому аргументу. (Это решение будет более эффективным, чем предыдущее, для тех версий Пролога, где осуществляется оптимизация остаточной рекурсии; см. приложение IV.)
% + + +
найти-слово (Слово, [Слово ! Список], Накопитель, Счетчик) :-
НовНакопитель is Накопитель + 1,
найти_слово (Слово, Список, НовНакопитель, Счетчик).
найти_слово (Слово, [ХСлово \ Список], Накопитель, Счетчик) :-
найти_слово (Слово, Список, Накопитель, Счетчик).
найти-слово (_, [ ], Накопитель, Накопитель).
% пример запроса:
| ?- найти-слово (the, [the, dog, in, the, barn], О, С).
C=2
5. длина ([пусто | R], Счетчик) :-
длина (R, Счетчик).
длина ([F | R], Счетчик) :-
длина (R, ТекущСчетчик),
Счетчик is ТекущСчетчик + 1.
длина ([ ], 0).
6. Возможные ответы к этому упражнению рассматриваются в гл.4.
7.
всего ([кл.(_-, Тариф, Дни) | Остаток], Итого) : -
всего (Остаток, ТекущСумма),
Итого is ТекущСумма + Тариф * Дни.
всего ([ ], 0).
8.
родитель (генри, джек).
родитель (джек, ричард).
родитель (ричард, чарльз).
родитель (чарльз, джейн).
пред(Х,Y,[Х,Y]):-родитель(Х,Y).
пред(Х,Y, [Х | Остаток]) :-
родитель (X,Z),
пред(Z, Y, Остаток) .
10.
% +
дд_в_списокс (дд (Имя, Отд,Долж, Окл, Предыдущ, Последующ) ,
%
ИтогСписок) :—
дд_в_список (Предыдущ, ПредыдСписок),
дд_в_список (Последующ, ПоследСписок),
присоедишить (ПредыдСписок, [cл (Имя, Отд, Долж, Окл)|
ПоследСписок], ИтогСписок).
дд_в_список (end, [ ]).
11. В процедуре "обр_печать" при унификации заголовков фраз выполняется сопоставление с эталоном, которое определяет условия применения фраз. В процедуре "нпредок" нет сопоставления с эталоном при унификации заголовков фраз, поэтому интерпретатор должен активировать тело фразы, чтобы определить, нужно ли использовать эту фразу.
Глава 3
1.
| ? путешествие (амтрак, нью_йорк, X, ),!,
путешествие (амтрак, X, Y, _).
2.
площадь (Основание, Высота, Площадь) :—
nonvar (Основание) > nonvar (Высота),
Площадь is Основание * Высота.
площадь (Основание, Высота, Площадь) :—
nonvar (Основание), nonvar (Площадь),
Высота is Площадь / Основание.
площадь (Основание, Высота, Площадь) :—
nonvar (Высота), nonvar (Площадь),
Основание is Площадь / Высота.
Если два из трех аргументов не будут конкретизированы, то задачу все равно можно решать, если воспользоваться процедурой, генерирующей целые числа. См. процедуру "ген_чисел" из приложения III.
3. Полное множество ответов должно состоять только лишь из ответов мери и бранен. Запрос А полон и неэффективен. Запрос Б неполон и неэффективен. Запрос В неполон и эффективен. Запрос Г и полон, и эффективен.
права (X) :-
шоферские_курсы (X),
возраст (X, 16).
права (X) :-
возраст (X, Возраст), Возраст > = 17.
4.
нью_йоркский_адрес (милфорд_плаза).
ныо_йоркский_адрес (конфуциус_плаза).
связывает (А, Б, такси) :—
нью_йоркский_адрес (А),
нью_ йоркский_адрес (Б ),
not (связывает (А, Б, автобус) ),
not (связывает (А, Б, поезд) ).
состояние (Машина, нормальное) :—
not (включен_аварийный_сигнал (Машина, Аварийныи_сигнал) ).
клиент (X,'AT&T') :-
имеет_телефон (X),
not (клиент (X, mci)),
not (клиент (X, sprint)).
5.
| ?- repeat,
write ('введите имя школьного товарища: '),
read (Имя),
( Имя = end % обход добавления факта
% "школьный_товарищ (end)".
;
assert (школьный_товарищ(Имя))
),
Имя = end,
!,
школьньй_товарищ (Имя),
write (Имя),nl,
fail.
6. Первый способ: база данных является множеством фактов.
сделка (смит, авиабилет, 139).
сделка (родригес, благотворительный_взнос, 25).
текущ_сумма (0).
% + -
сумма_сделки (Имя, Сумма) :—
сделка (Имя, __, Стоимость),
один_раз (retract (текущ_сумма (Текущ) )),
НовТекущ is Текущ + Стоимость,
assert (текущ_сумма (НовТекущ) ),
fail.
сумма_сделки (Имя, Сумма) :-
retract (текущ_ сумма (Сумма)),
assert (текущ_сумма (0) ).
Второй способ: база данных является списком структур. Для удобства проверки этот список хранится в программе в виде факта "список".
список ([сд (смит, авиабилет, 139),
сд (родригес, благотворительный_взнос, 25)]).
% + ?
р_сумма_сделки ([сд (Имя, __, Стоимость) | Остаток], Имя, Сумма) :-
р_сумма_сделки (Остаток, Имя, ТекущСумма),
Сумма is ТекущСумма + Стоимость.
р_сумма_сделки([сд(ХИмя,_ , Стоимость) | Остаток], Имя, Сумма) :—
ХИмя \== Имя,
р_сумма сделки (Остаток, Имя, Сумма).
р_сумма_сделки([ ],_, 0).
| ?— список (L), р_сумма_сделки (L, смит, Итого).
Итого =139
8.
список путешествий (
[п(амтрак, нью_йорк, бостон, поезд),
п(ндж_транзит, нью_йорк, принстон, поезд),
п(амтрак, бостон, портленд, поезд),
п(грейхаунд, бостон, портленд, автобус),
п(амтрак, нью_йорк, Вашингтон, поезд),
п(пиплз, нью_йорк, Вашингтон, самолет),
п(пиплз, бирлингтон, нью_йорк, самолет)]).
можно_путешествовать(ГородА, ГородБ, Список) :-
элемент (п(_, ГородА, ГородБ, _), Список).
можно_путешествовать(ГородА, ГородБ, Список) :-
элемент (п (_, ГородА, ГородВ, _), Список),
можно_путешествовать(ГородВ, ГородБ, Список).
|?— список_путешествий (СП),
можно_путешествовать(нью_йорк, портленд, СП).
9.
% Многие Один группа0 (генри, компиляторы).
группа0(нэнси, компиляторы).
группа0 (сюзан, сети).
группа (Имя, Группа) :~
nonvar (Имя),
группа0 (Имя, Группа),!.
группа (Имя, Группа) :—
vаг(Имя),
группа0 (Имя, Группа).
группа (Имя, Группа) :~
not (группа0 (Имя, Группа) ),
( vаг(Имя),
write ('имя?'),
read (Имя),
;
nonvar (Имя)
),
( var( Группа),
write ('группа? '),
read (Группа),
; nonvar (Группа)
),
assert (группа0 (Имя, Группа)).
11.
:-ор (500, xfy, —). :-
op(499,xfy, ->).
можно_путешествовать5 (А, Б, (А— Вид_тр—>Б)) :—
путешествие (_, А, Б, Вид_тр).
можно_путешествовать5(А, Б, (А—Вид_тр— >Рпуть)) :—
путешествие (_, А, В, Вид_тр),
можно_путешествовать5 (В, Б, Рпуть).
Гл а в а 4
1. Ниже приводятся новые версии базы данных и процедур, в которых учитывается расстояние.
% Из В Транспорт Мили
путешествие (манхэттен, ньюарк, автобус, 15).
путешествие (манхэттен, куинс, жел_дорога, 5).
путешествие (ньюарк, бронкс, автомобиль, 25).
путешествие (бронкс, куинс, автобус, 8)
путешествие (манхэттен, бронкс, метро, 4).
путешествие (ньюарк, принстон, автомобиль, 35).
путешествие (манхэттен, принстон, автобус, 50).
% Обеспечение симметрии запросов к базе данных
% ''путешествием"
сим_путешествие (А, Б, Вид_тр, Мили) :-
путешествие (А, Б, Вид_тр, Мили).
сим_путешествие (А, Б, Вид_тр, Мили) : —
путешествие (Б, А, Вид_тр, Мили).
% . + + + -
тснр_путешествовать3 (След, А, Б, Мили—м (Вид_тр, Б)) :— % (1)
А\==Б,
сим путешествие (А, Б, Вид_тр,Мили).
тснр_путешествоватьЗ(След, А, Б, Мили—м(Вид_тр1,В,Вид_тр2) :- % (2)
А \ == Б,
сим_путешествие(А, В, Вид_тр1, Мили1), % генерировать В
not (элемент (В, След) ), % проверить В
тснр_путешествовать3 ([В | След], В, Б, Мили2—Видтр2),
Мили is Мили1 + Мили2.
Рекурсивное решение:
р_наилучший_маршрут(А, Б, Маршрут) :—
findall (Вид_тр,
тснр_путешествовать3 ([ ], А, Б, Вид_тр),
Список),
keysort (Список, ОрсортСписок),
ОтсортСписок = [Маршрут [ _ ] •
Решение, в котором используется поиск с возвратом:
оптимальный_маршрут (_, 100000).
наилучший_маршрут(А, Б, Маршрут) :—
тснр_путешествовать3 ([ ], А, Б, Мили—Маршрут),
один_раз (оптимальный_маршрут(ОптМаршрут, ОптМили)),
( Мили < ОптМили,
один_ раз (retract (оптимальный_маршрут(, _))) ,
assert (оптимальный_маршрут (Маршрут, Мили))
;
Мили>= ОптМили
),
fail.
наилучший_маршрут(А, Б, Маршрут) :-
retract (оптимальный_маршрут (Маршрут, )),
assert (оптимальный_маршрут(_, 100000)).
Если в Вашей версии Пролога достаточно эффективно реализован встроенный предикат "key sort", то рекурсивная версия программы будет выполняться более быстро. Версия программы в которой используется поиск с возвратом, потребует меньшего объема памяти. Рекурсивное решение основывается на подходе к программе с позиций потока данных, а решение, в котором используется поиск с возвратом, — на бихевиористическом подходе.
2. Нижеследующее правило "можно_запрашивать" охватывает случай, когда пункт отправления неизвестен:
% неизвестен пункт отправления:
можно_запрашивать (путешествие (А, Б> Вид_тр),
'введите пункт отправления: ',
А):-
non var (Вид_тр), non var (Б).
Далее приводится версия процедуры "найти_или_спросить", которая может работать с любым количеством неизвестных аргументов. Вторым аргументом факта "можно_запрашивать2" является список подсказок — по одной на каждый аргумент факта "путешествие".
можно_запрашивать2 (путешествие (Исх_пункт, Пункт_назнач, Вид_тр),
['откуда?', 'куда?', 'вид транспорта?'']).
найти_или_спросить2 (Запрос) :- Запрос.
найти_или_спросить2 (Запрос) :-
not(3anpoc), % это правило вступает в силу, если
% запрос терпит неудачу
можно_запрашивать2 (Запрос, СписокПодсказок),
Запрос = .. [Пред | СписокАрг],
проверить_каждый (СписокАрг, СписокПодсказок),
assert (Запрос).
проверить_ каждый ([Арг | СписокАрг],
[Подсказка ; СписокПодсказок]) :-
( var (Арг),
write (Подсказка),
read (Арг)
;
nonvar (Арг)
),
!, проверить_каждый (СписокАрг, СписокПодсказок).
проверить каждый ([ ], _).