Опубликован: 12.02.2014 | Доступ: свободный | Студентов: 818 / 236 | Длительность: 11:22:00
Специальности: Программист
Лекция 6:

Списки. Полиморфизм

< Лекция 5 || Лекция 6: 123 || Лекция 7 >
Аннотация: Списки в языке Пролог являются одной из основных структур данных. Рекурсивная природа списков предполагает их рекурсивную обработку. Рассматриваются понятия полиморфизма и параметрического полиморфизма. Определяются основные полиморфные предикаты обработки списка.

Списки в языке Пролог являются одной из основных структур данных. Рекурсивная природа списков предполагает их рекурсивную обработку. В данной главе рассматриваются понятия полиморфизма и параметрического полиморфизма. Определяются предикаты обработки списка — полиморфные предикаты вычисления длины списка, определения принадлежности элемента списку, соединения списков, замены элементов списка, обращения списка, удаления элементов из списка, а также недетерминированные предикаты поиска подсписков списка, его префиксов и суффиксов, и предикат возвращения произвольного элемента списка и его остатка либо вставки элемента в произвольное место списка.

6.1. Параметрический полиморфизм

Если природа элементов списка не важна, как, например, при вычислении длины списка, то для объявления предиката обработки списков обычно используются полиморфные домены. Рекурсивно длина списка определяется как сумма длины хвоста списка и единицы, длина пустого списка равна нулю (см. ниже).

Имя полиморфного домена в объявлении предиката пишется с прописной буквы в виде:

class predicates
    length: (Elem*) -> positive.

Имя Elem можно заменить любым другим именем, начинающимся с прописной буквы, например:

class predicates
    length: (A*) -> positive.

Переменная (Elem или A) обозначает произвольный домен элементов списка. Предикаты, аргументы которых могут принадлежать произвольным доменам, называются полиморфными предикатами. Определение пролиморфного предиката не зависит от природы его аргументов. Например, предикат вычисления длины списка одинаково определяется для списка чисел, списка строк и т. д. Но предикат, который вычисляет сумму элементов списка, не может быть полиморфным, так как в его определении участвует операция сложения чисел, которая не применима, например, к строкам (напомним, что все элементы списка должны принадлежать одному и тому же домену). Полиморфизм, в котором предикаты определяются независимо от типа аргументов, называется параметрическим.

6.2. Параметры в именах доменов

Имена доменов могут иметь аргументы — параметры, которые представляют также имена доменов. В качестве аргументов имени домена в объявлении этого домена могут указываться только переменные. Аргументы имен доменов заключаются в фигурные скобки, они являются попарно независимыми. Например, объявление предикатного домена и принадлежащих ему предикатов может иметь вид:

domains
    op{A, B} = (A*) -> B.

class predicates
    length : op{A, positive}.    % длина списка
    sum : op{integer, integer}.    % сумма элементов списка
clauses
    length([]) = 0.
    length([_ | T]) = 1 + length(T).

    sum([]) = 0.
    sum([H | T]) = H + sum(T).

Функции вычисления длины списка и суммы его элементов определены выше без применения хвостовой рекурсии. Поэтому их нельзя использовать для списков, содержащих сотни тысяч или миллионы элементов. Эффективное определение этих операций, с использованием счетчика, позволяет сделать это (листинг 6.1). В программе используется хвостовая рекурсия.

class predicates
    length: (A*) -> positive.
    length: (A*, positive) -> positive.
clauses
    length(L) = length(L, 0).

    length([], N) = N.
    length([_ | T], N) = length(T, N + 1).

    run():-
        write(length([1, 2, 3]) + length(["A", "B"])),
        _ = readLine().
Пример 6.1. Длина списка

Упражнение 1. Определите предикат, вычисляющий сумму четных элементов списка с помощью хвостовой рекурсии.

В следующей программе определяются операции проверки принадлежности элемента списку, а также возвращения произвольного элемента списка, в предикатном и в функциональном стиле. Операция определяется рекурсивно, в соответствии с правилом — элемент принадлежит списку, если он совпадает с головой списка или принадлежит его хвосту.

class predicates
    member_dt: (A, A*) determ.
    member: (A [out], A*) nondeterm.
    member_nd: (A*) -> A nondeterm.
clauses
    member_dt(H, [H | _]):- !.   % проверка принадлежности
    member_dt(H, [_ | T]):-
        member_dt(H, T).

    member(H, [H | _]).    % возвращение элемента списка
    member(H, [_ | T]):-
        member(H, T).

    member_nd([H | _]) = H.
    member_nd([_ | T]) = member_nd(T).

    run():-
        X = 2, L = [1, 2, 3],
        if member_dt(X, L) then
            writef("Элемент % принадлежит списку %\n\n", X, L)
        else
            writef("Элемент % не принадлежит списку %\n\n", X, L)
        end if,

        writef("Элементы списка %:\n", L),
        foreach member(Y, L) do
            write(Y), nl
        end foreach,

        L1 = ["H", "E", "L", "L", "O"],
        writef("\nЭлементы списка %:\n", L1),
        write(member_nd(L1)), nl,
        fail;
        _ = readLine().
Пример 6.2. Принадлежность элемента списку
< Лекция 5 || Лекция 6: 123 || Лекция 7 >
Жаныл Айкын
Жаныл Айкын
Rustam Inatov
Rustam Inatov

Доброго времени суток, подскажите пожалуйста, visual prolog examples, pie, vip7.5 - это все, где я могу скачать? (в смысле) может быть на сайте есть какой-то архив? Увы я не нашел его.

Подскажите, пожалуйста.

С уважением, Рустам.