Волченков Логическое программирование язык пролог 2015
.pdfОтвет:
W = 'zy#$#%$%%^&877665534456578hyt'
vv(W):-get0(X), vv1([X],L,X), name(W, L), vv2(L), nl.
vv1(L, L, 122). % 122 – код символа z vv1(B, L, X):- get0(Y), vv1([Y|B], L, Y).
vv2([]) :- !.
vv2([C|T]) :- put(C), vv2(T).
| ?- vv(W).
|: abcdefgh12345!@#$%yz zy%$#@!54321hgfedcba
W = 'zy%$#@!54321hgfedcba'
Встроенные предикаты управления. Методы реализации циклов
Задача 3. В базу данных Пролога загружены факты о преподавателях кафедры «Кибернетика» НИЯУ МИФИ со спецификацией prep/10. Напечатать все эти факты «в столбик». (Использовать возвратный метод организации цикла.)
Решение:
печать_факта(F, N) :- functor(S, F, N), печать_факта(S).
печать_факта(S) :- call(S), write(S), nl, fail.
печать_факта(_).
Задача 4. В базу данных Пролога загружены факты о преподавателях кафедры «Кибернетика» НИЯУ МИФИ со спецификацией prep/10. Факты отсортированы по возрастанию ФИО (2-й аргумент). Напечатать «в столбик» факты, у которых значение ФИО =< ’Щукин Б.А.’. (Использовать метод CAF организации цикла.)
Решение:
печать_факта(F, N) :- functor(S, F, N), печать_факта(S).
печать_факта(S) :- call(S), write(S), nl, arg(2, S, ’Щукин Б.А.’), !.
61
Задача 5. Печатать «в столбик» целые случайные числа от 0 до 99 до тех пор, пока не появится число, превышающее 90. (Использовать метод UDR организации цикла.)
Решение:
печать_случайного_числа :- repeat, rrr(X), X>90. rrr(X) :- X is int(rand(100)), !.
Предикаты преобразования структур
Выше были рассмотрены четыре предиката из категории преобразования структур. Рассмотрим задачи, в которых они используются.
Предикат name/2
Отметим, что в поздних версиях Пролога, в частности, в LPA WIN-PROLOG 4.200 атомы можно строить из строчной «кирилли-
цы»:
| ?- name(еёжз, X).
X = [1077,1105,1078,1079]
| ?- name(X, [1077,1105,1078,1079]).
X = еёжз
Задача 6.
Замените в 1-м вызове 2-й аргумент на _еёжз. Что ответит Про- лог-система?
Замените во 2-м вызове 1-й аргумент на _еёжз, а 2-й аргумент на
[95,1077,1105,1078,1079]. Что ответит Пролог-система?
Что Пролог-система ответит на вызов: ?- name('_еёжз', _еёжз).
Ответ:
| ?- name('_еёжз', _еёжз).
_еёжз = [95,1077,1105,1078,1079]
Предикат functor/3
Задача 7.
Ранее были приведены примеры вызова данного предиката:
? – functor(f(a, b, c), X, Y). |
→ |
X = f, Y = 3 |
? – functor(X, f, 3). → |
X = f(_, _, _) |
|
|
62 |
|
Замените в 1-м вызове f(a, b, c) на 1+2+3+4.
Замените во 2-м вызове f на is, 3 на 2. Что получится в результате?
Ответ:
В результате получится: в 1-м вызове: X = ’+’, Y = 2; во 2-м вызове: X = _ is _.
Предикат arg/3.
Напомним, что в отличие от предыдущих предикатов этот предикат работает только в одну сторону: его спецификация arg/(i, i, o). По номеру компонента (1-й аргумент) структуры произвольного вида (2-й аргумент) находится значение этого компонента (3-й ар-
гумент). Но не наоборот. |
|
? – arg(2, f(a, b, c), X). → |
X = b |
Задача 8. Напишите определение предиката arg1/(?, i, ?). Точнее, спецификация этого предиката должна быть либо arg1/(i, i, o),
либо arg1/(o, i, i).
Указание: можно использовать встроенный предикат var/1, проверяющий, не является ли терм неозначенной переменной.
Ответ:
% S – всегда входной параметр (исходная структура).
arg1(N, S, X) :- var(N), !, % (o, i, i) – по значению аргумента
functor(S, _, A), |
% ищем его номер |
arg1(1, A, N, S, X). |
|
arg1(N, S, X) :- !, |
% (i, i, ?) – по номеру аргумента |
arg(N, S, X). % ищем (или проверяем) его значение
arg1(I, A, _, _, _) :- I > A, !, fail. arg1(N, _, N, S, X) :- arg(N, S, X).
arg1(I, A, N, S, X) :- I1 is I + 1, arg1(I1, A, N, S, X).
63
Консоль:
| ?-
# 0.000 seconds to consult arg1.pl [c:\prolog\lpa\] | ?- arg1(3, f(a,b,c,b), c).
yes
| ?- arg1(3, f(a,b,c,b), b). no
| ?- arg1(3, f(a,b,c,b), X). X = c
| ?- arg1(X, f(a,b,c,b), b). X = 2 ;
X = 4 ; no
Предикат =../2.
Напомним, что этот предикат осуществляет преобразование структуры произвольного вида (1-й аргумент) в список (2-й аргумент), или наоборот. 1-й элемент списка – имя структуры, 2-й элемент – компоненты структуры. Таким образом, длина списка на единицу больше числа компонентов структуры.
? – f(a, b, c) =.. X. |
→ |
X = [f, a, b, c] |
? – X =.. [f, a, b, c]. |
→ |
X = f(a, b, c) |
Задача 9. В базе данных Пролога есть данные о преподавателях кафедры «Кибернетика» МИФИ в виде фактов prep/10. Второй аргумент этой структуры данных – ФИО преподавателя. Не пользуясь предикатом arg/3, найдите шифр (значение 1-го аргумента) и должность (значение 3-го аргумента) преподавателя Щукина Б.А.
Ответ:
? – functor(P, prep, 10), call(P), P =.. [X, ’Щукин Б.А.’, Y|_].
64
Методы и примеры определений предикатов обработки списков
В разд.2 данной лекции были приведены определения предика-
тов обработки списков: member/2, append/3, reverse/2, sort/2 и т.д.
Задача 10. Напишите определение предиката sort_k/(i, o, i) для сортировки списка термов t/(a1, ..., an) по ключу: (ai, ..., aj). Ключ – список целых чисел – номеров аргументов терма, по которым производится сортировка. Для проверки определите вспомогательный предикат test/3, с помощью которого задаётся проверочная информация, например:
test(List, SortedList, Key) :- K=[2, 3], List=[f(d,m,8), f(d,m,3), f(d,k,9)], sort_k(List, SortedList, Key).
Ответ:
%Сортировка списка термов t/(a1, ..., an)
%по ключу: (ai, ..., aj).
sort_k([], [], _) :- !.
sort_k([T|Ts], Res, Key) :- sort_k(Ts, Res1, Key), in_sort_k(T, Res1, Res, Key).
in_sort_k(T, [], [T], _).
in_sort_k(T, [H|R], [T, H|R], K) :- less_eq_k(T, H, K),!. in_sort_k(T, [H|R], [H|R1], K) :- !,
in_sort_k(T, R, R1, K).
less_eq_k(X, Y, K) :- lista(X, K, L1), lista(Y, K, L2), L1 @=< L2, !.
lista(_, [], []) :- !.
lista(T, [N|K], [A|L]) :- arg(N, T, A), lista(T, K, L).
65
Консоль:
# 0.000 seconds to consult sort_k.pl [c:\prolog\lpa\] | ?- test(List, Res, Key).
List = [f(d,m,8),f(d,m,3),f(d,k,9)] , Res = [f(d,k,9),f(d,m,3),f(d,m,8)] , Key = [2,3]
yes
Задача 11. Дан список списков list_lists([L1, …, Ln]), где Li – список термов.
Декларативно (!) определите предикаты maxlist/1 и minlist/1, выходной параметр которых – максимальный и минимальный по длине список из данного списка списков.
Указание: используйте определения предикатов longer(X,Y) и shorter(X,Y), с помощью которых списки сравниваются по длине (а также создаются списки, более длинные или более короткие, чем данный список):
longer([_|_], []).
longer([_|L1], [_|L2]) :- longer(L1, L2).
shorter([], [_|_]).
shorter([_|L1], [_|L2]) :- shorter(L1, L2).
Решение:
maxlist(L) :- list_lists(Ls), member(L, Ls), nolonger(L, Ls). nolonger(L, Ls) :- longer(M, L), member(M, Ls), !, fail.
% Предикат «нет списка длиннее» nolonger(_, _) :- !.
minlist(L) :- list_lists(Ls), member(L, Ls), noshorter(L, Ls). noshorter(L, Ls) :- shorter(M, L), member(M, Ls), !, fail.
% Предикат «нет списка короче»
noshorter(_, _) :- !.
longer([_|_], []).
longer([_|L1], [_|L2]) :- longer(L1, L2).
66
shorter([], [_|_]).
shorter([_|L1], [_|L2]) :- shorter(L1, L2).
Применение методов исходящей и входящей рекурсии в Прологе
Автор предлагает слушателям и читателям ответить на вопросы относительно использования методов входящей и выходящей рекурсии в задачах 8 – 11.
Вопрос 1. Какой из двух методов рекурсии используется в определении предиката arg1/3 ? ( Задача 8.)
Ответ: метод входящей рекурсии.
Вопрос 2. Какой из двух методов рекурсии используется в определении предиката sort_k/3 – сортировки списка термов по заданному ключу и в рекурсивных определениях трёх предикатов: sort_k/3, in_sort_k/4 и lista/3? ( Задача 10.)
Ответ: метод исходящей рекурсии.
Вопрос 3. Какой из двух методов рекурсии используется в определениях предикатов shorter/2 и longer/2? ( Задача 11.)
Ответ: метод исходящей рекурсии.
Задача 12. С помощью метода входящей рекурсии определите предикаты minlist/1 и maxlist/1. В этих определениях используйте традиционный для языков операторного типа способ нахождения максимального и минимального элементов (массива, например).
Указание: можно использовать встроенный предикат length(L, N) для определения длины N списка L.
Решение (одно из многих возможных):
% Тестовый пример списка списков: list_lists([[a,b],[c,d,e],[f],[g,h,i],[j],[k,l,m],[o],[p,q]]).
minlist(X) :- list_lists([L|Ls]), length(L, N), singlemin(N, M, Ls),
%Безвозвратный поиск длины минимального списка.
!, multim(M, X, [L|Ls]).
%Возвратный поиск всех списков данной длины.
67
maxlist(X) :- list_lists([L|Ls]), length(L, N), singlemax(N, M, Ls),
%Безвозвратный поиск длины максимального списка.
!, multim(M, X, [L|Ls]).
%Возвратный поиск всех списков данной длины.
singlemin(N, N, []) :- !. |
% Входящая рекурсия. |
singlemin(N, M, [L|Ls]) :- |
% Операторный стиль. |
length(L, K), K<N, !, singlemin(K, M, Ls). singlemin(N, M, [L|Ls]) :-
!, singlemin(N, M, Ls).
% Отсечение обеспечивает безвозвратность.
singlemax(N, N, []) :- !. |
% Входящая рекурсия. |
singlemax(N, M, [L|Ls]) :- |
% Операторный стиль. |
length(L, K), K>N, !, singlemax(K, M, Ls). singlemax(N, M, [L|Ls]) :-
!, singlemax(N, M, Ls).
% Отсечение обеспечивает безвозвратность.
multim(M, X, Ls) :- member(X, Ls), length(X, M).
% Поиск всех решений.
Консоль:
| ?-
# 0.000 seconds to consult minmaxls.pl [c:\prolog\lpa\] | ?- minlist(X).
X = [f] ; X = [j] ; X = [o] ; no
| ?- maxlist(X). X = [c,d,e] ; X = [g,h,i] ;
X = [k,l,m] ; no
68
Подумайте, какой из двух представленных выше стилей решения данной задачи (декларативный или процедурный) более красив, а какой стиль более эффективен?
69
Лекция 5
Синтаксический анализ на Прологе
В данной лекции рассматривается возможность использования Пролога для синтаксического анализа языков, представляемых формальными грамматиками, – контекстно-свободных и контекст- но-зависимых языков. Прежде всего, даётся определение порождающей грамматики. Определяются автоматная, контекстносвободная и контекстно-зависимая грамматики, а также языки соответствующих трёх типов. На примере показано, как можно реализовать на Прологе простейший анализатор для автоматного языка, – эта задача не представляет большого интереса. Рассматривается попытка создания «наивного» анализатора для КС-грамматики с помощью недетерминированного разбиения цепочки на подцепочки. Показано, что использование малоэффективного предиката append/3 делает такой анализатор бесперспективным. Наконец, рассказывается об идее замены указанного предиката разностными списками и, в частности, механизмом DCG – Definite Clause Grammar. Это приводит к возможности создания эффективно работающих нисходящих грамматических разборщиков на Прологе.
1. Формальные грамматики и языки
Вспомним определения порождающей грамматики и языка, порождаемого такой грамматикой.
Порождающей грамматикой называется следующая четверка:
G = <VT, VN, S, P>,
где VT, VN – соответственно, терминальный и нетерминальный словари, S – начальный символ, P = { i i} – множество правил вывода, причём i – цепочка, содержащая нетерминальный символ,i – произвольная цепочка из терминальных и нетерминальных символов.
Непосредственным порождением называется отношение
70