Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Spec_Mov_3k_4k_Lect.doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
1.46 Mб
Скачать

Вопросы для самоконтроля

  • Перечислите разделы Турбо-Пролог программы!

  • Какие имеются способы указания областей определения предикатов?

  • Перечислите стандартные домены используемые в Турбо-Пролог программах!

  • Приведите пример переименования областей и определения списков символов!

  • Что из себя представляет «рекурсивная программа» в логической программе?

  • Как в программе указываются разделы доменов, предикатов и правил (клозов)?

  • Строится ли в пролог-программе точка решения (ветвления) для внелогических предикатов?

  • Отменяется ли действие, вызванное внелогическим предикатом при выполнении возврата в процессе поиска решения?

  • Приведите пример дополнения домена file символами input, output и ownerrs!

Вопросы на самостоятельную проработку

  • Изучить имеющиеся в Турбо-Прологе арифметические предикаты и предикаты для работы со строками!

  • Изучить имеющиеся в Турбо-Прологе предикаты для работы с файлами openread, openwrite, openmodify, openappend, readdevice, writedevice, readln, write, eof и др.!

К оглавлению

Лекция 4. Списки и управление выводом в Турбо-Пролог-программах Списки

Все структурные объекты Пролога представлены деревьями. Списки также представлены деревьями. В качестве обозначения терма, связанного с представлением списков используется точка «.». Непустые списки имеют голову и хвост. Пустой список представлен парой квадратных скобок: [].

Примеры

Список из одного элемента, содержащий атом а: .(a, []). Эквивалентная форма представления этого же списка: [a].

Список из 2-х элементов можно представить следующими способами:

.(a, .(b, [])) или более лаконично - [a, b].

Описания списков

Домены списков декларируются в секции пролог-программы domains. Если после имени базового домена указывается звездочка, то это означает, что декларирован домен включающий списки базовых объектов.

Пример

domains

lst1 = symbol*

lst2 = string*

Домены lst1 и lst2 содержат, соответственно, списки символьных атомов и списки строковых объектов.

Шаблон для работы со списками

На практике удобно трактовать хвост списка как самостоятельный объект. Например, для списка [a, b, c, d], его головой является атом a, а хвостом – список [b, c, d]. В языке Пролог имеется объект специального вида – шаблон, который унифицируется со списками и позволяет выделять из списка отдельные элементы.

Примеры

Если список [a, b, c, d] унифицируется с шаблоном [a | X], то переменная Х унифицируется списком [b, c, d]. Предположим необходимо выделить голову списка и хвост. Тогда для сопоставления необходимо применить шаблон следующего вида: [H | T]. Тогда переменная H унифицируется символьным атомом a, а переменная T – списком списка [b, c, d].

Примеры программ работы со списками

Рассмотрим некоторые программы, в которых постоянно используется шаблон вида [… | …] для работы со списками.

Пример 1

Необходимо дать определение предиката ins(X, L), который вычисляет принадлежность символьного атома Х списку L.

Решение подобных задач лучше всего начинать со словесной формулировки решения и затем перейти к программной реализации:

  1. X – голова списка L или

  2. X – принадлежит хвосту списка L.

Имеем следующий результат:

domains

lst = symbol*

predicates

ins(symbol, lst)

clauses

ins(X, [X | Tail]).

ins(X, [Y | Tail]):- X<>Y, ins(X, Tail).

Пример 2

Необходимо представить реализацию предиката conc(L1, L2, L3), в котором L3 представляет сцепление списков L1 и L2.

Решение можно записать в следующем виде:

  1. Если L1 пуст, то L3 совпадает с L2.

  2. Если L1 не пуст, то он имеет голову X1 и хвост T1; результирующий список имеет голову X1 и хвост, который является результатом сцепления T1 и L2.

domains

lst = string*

predicates

conc(lst, lst, lst)

clauses

conc([], L, L).

conc([X1 | T1], L2, [X1 | T3]):- conc(T1, L2, T3).

Предикат conc можно применять в различных ситуациях:

  • для сцепления 2-х списков, например так:

goal

conc([“a”, ‘b”], [“cd”, “ef”], Lst). // результат будет унифицирован с Lst

  • для расщепления списков, например так:

goal

conc(Lf, Ls, [“a”, “bc”, “d”]).

Все способы расщепления исходного списка будут представлены значениями переменных Lf и Ls.

Предикат conc может использоваться в качестве основы для реализации других предикатов:

  • определение принадлежности элемента списку:

ins(X, Lst):- conc(_, [X | Tail], Lst).

«Элемент принадлежит списку, если возможно расщепление списка таким образом что элемент является головой второго подсписка»,

  • являются ли элементы соседними в списке:

adjacent(X, Y, Lst):- conc(Lf, [X, Y | _], Lst).

  • является ли элемент последним в списке:

last(X, Lst):- conc(_, [X], Lst).

«2-й подсписок содержит один элемент совпадающий с X»

Пример 3

Из списка целых необходимо удалить один указанный элемент.

domains

lint = integer*

predicates

delete(integer, lint, lint)

clauses

delete(X, [], []).

delete(X, [X | Tf], Lr):- delete(X, Tf, Lr).

delete(X, [Y | Tf], [Y | Lr]):- X<>Y, delete(X, Tf, Lr).

Словесное решение выглядит следующим образом:

  1. Если исходный список пуст, то и результат – пустой список.

  2. Если выбрасываемый элемент первый в исходном списке, то результирующий список будет получен выбрасыванием этого элемента как из головы, так и из хвоста списка.

  3. Если элемент не совпадает с первым элементом в списке, то необходимо выполнить сцепление первого элемента списка со списком, полученным в результате выбрасывания элемента из хвоста списка.

«Рекурсивные определения» м.б. использованы и для сортировки.

Пример 4

Необходимо выполнить сортировку вставкой. Сортируется список символьных атомов – sort(L1, L2) – L2 является результатом сортировки L1.

Решение:

  1. Если L1 пуст, то и L2 пуст.

  2. Если L1 не пуст, то можно сортировать хвост списка и затем выполнить вставку головного элемента списка в «правильное» место сортированного списка, сохраняющее упорядоченность списка.

Для упрощения реализации программы воспользуемся вспомогательным предикатом vst(H, L1, L2), который обеспечивает вставку элемента H в список L1; результатом вставки элемента является список L2. В основу разработки предиката vst положены следующие рассуждения:

  1. Если L1 пуст, то результатом является одноэлементный список [H].

  2. Если список L1 не пуст, то:

  • L1 является хвостом списка L2, если H меньше или равен головному элементу списка L1, иначе

  • головные элементы L1 и L2 совпадают и хвост списка L2 является результатом вставки символа H в хвост списка L1.

domains

lst = symbol*

predicates

sort(lst, lst)

vst(symbol, lst, lst)

le(symbol, lst)

clauses

sort([], []).

sort([H | T], Rez):- sort(T, Rez1), vst(H, Rez1, Rez).

vst(S, [], [S]).

vst(S, X, [S | X):- le(S, X).

vst(S, [H | T], [H | Rez):- not(le(S, [H | T])), vst(S, T, Rez).

le(S, [H | T]):- S<= H.

goal

sort([a, c, d, f, e], X).

Необходимо самостоятельно выполнить реализацию предиката vst согласно представленного выше описания!

Пример 5

Необходимо выполнить разработку логической программы, выполняющей обменную сортировку (сортироваться должны символьные атомы).

Общая характеристика метода сортировки следующая:

  1. Выбирается 1-й элемент списка и хвост списка разделяется на 2 подсписка, в котором, в первом подсписке все элементы меньше выбранного элемента, а во втором – все остальные элементы.

  2. Рекурсивно (аналогично пп.1) выполняется сортировка подсписков.

  3. Сортированные подсписки объединяются, причём выбранный элемент вставляется между сортированными подсписками.

domains

lst = symbol*

predicates

sort(lst, lst)

part(symbol, lst, lst, lst)

conc(lst, lst, lst)

clauses

sort([], []).

sort([HX| L0], L):- part(X, L0, U1, U2), sort(U1, V1), sort(U2, V2),

conc(V1,[X | V2], L).

part(X, [], [], []).

part(X, [H | L], [H | V1], V2):- H < V, part(X, L, V1, V2).

part(X, [H | L], V1, [H | V2]):- X <= H, part(X, L, V1,V2).

Реализацию conc выполнить самостоятельно, взяв в качестве образца одну из реализаций, представленных в начале лекции.

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