Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Волченков Логическое программирование язык пролог 2015

.pdf
Скачиваний:
11
Добавлен:
12.11.2022
Размер:
4.14 Mб
Скачать

Ответ:

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

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