Скачиваний:
23
Добавлен:
22.05.2015
Размер:
137.73 Кб
Скачать

Обработка списков

Обработка списков обычно производится рекурсивно. На каждом витке рекурсивного цикла обрабатывается один или несколько смежных элементов. Как правило, на вход такого предиката подаётся один или несколько обрабатываемых списков. На выходе предиката – один или несколько выходных списков.

Пример 4. Возведение в квадрат каждого элемента входного списка:

implement main

    open core, console

constants

className = "com/visual-prolog/main".

classVersion = "$JustDate: $$Revision: $".

class predicates

квадрат : (integer* ВходнойСписок) -> integer* СписокКвадратов.

clauses

classInfo(className, classVersion).

квадрат([I|L])=[I*I|квадрат(L)].

квадрат([])=[].

run():-init(),

   write(квадрат([10,20,30])),

   _=readchar().

end implement main

goal

   mainExe::run(main::run).

Пример 5. Расщепить заданный список на два списка. Один должен содержать только нечётные элементы исходного списка, другой – только чётные:

implement main

    open core, console

constants

className = "com/visual-prolog/main".

classVersion = "$JustDate: $$Revision: $".

class predicates

чётНечёт : (integer* ВходнойСписок, integer* СписокНечёт,  integer* СписокЧёт) procedure (i,o,o).

clauses

classInfo(className, classVersion).

чётНечёт([I|L],[I|Нечёт],Чёт) :- I mod 2 = 1,!, чётНечёт(L,Нечёт,Чёт).

чётНечёт([I|L],Нечёт,[I|Чёт]) :- чётНечёт(L,Нечёт,Чёт).

чётНечёт([],[],[]).

run():-

   init(),

   чётНечёт([1,2,3,4,5,6,7,8],Нечёт,Чёт),

   write(Нечёт),nl,

   write(Чёт),nl,

   _=readchar().

end implement main

goal

   mainExe::run(main::run).

Пример 6. Расщепить заданный список на два списка. Один должен содержать элементы, находящиеся на нечётных позициях исходного списка, другой – на чётных позициях:

implement main

    open core, console

constants

className = "com/visual-prolog/main".

classVersion = "$JustDate: $$Revision: $".

class predicates

позиц : (integer* ВходнойСписок, integer* НечётПозиц, integer* ЧётПозиц) procedure (i,o,o).

clauses

classInfo(className, classVersion).

позиц([X,Y|L],[X|Нечёт],[Y|Чёт]) :- !,позиц(L,Нечёт,Чёт).

позиц(L,L,[]).

run():-init(),

   позиц([1,3,5,7,9,0,-1,-2],Нечёт,Чёт),

   write(Нечёт),nl,

   write(Чёт),nl,

   _=readchar().

end implement main

goal

   mainExe::run(main::run).

Пример 7. Поменять местами элементы, находящиеся на нечётных позициях исходного списка с элементами, находящимися на чётных позициях, то есть первый элемент со вторым, третий – с четвёртым и т.д.:

implement main

    open core, console

constants

className = "com/visual-prolog/main".

classVersion = "$JustDate: $$Revision: $".

class predicates

замена : (integer* ВходнойСписок, integer* ВыходнойСписок) procedure (i,o).

clauses

classInfo(className, classVersion).

замена([X,Y|L],[Y,X|W]) :- !,замена(L,W).

замена(L,L).

run():-init(),

   замена([1,2,3,4,5,6,7,8,9],L),

   write(L),nl,

   _=readchar().

end implement main

goal

   mainExe::run(main::run).

Пример 8. “Наивный” реверс списка:

implement main

open core, console

constants

className = "com/visual-prolog/main".

classVersion = "$JustDate: $$Revision: $".

class predicates

rev : (integer* ВходнойСписок, integer* РеверсСписок).

clauses

classInfo(className, classVersion).

rev([X|L],R) :- !,rev(L,[X|R]).

rev(_,R) :- write(R).

run():-init(),

   rev([1,2,3,4,5,6,7,8,9],[]),

   _=readchar().

end implement main

goal

   mainExe::run(main::run).

Представленный реверс является “наивным”. Дело в том, что дополняя слева пустой список элементами входного списка, мы получаем реверсированный список только на дне рекурсии, то есть тогда, когда исходный список выбран до последнего элемента. Однако в рассматриваемом предикате rev не предусмотрено вспомогательной переменной, через которую можно “вытащить” результат наверх, в начало рекурсии. Поэтому то нам и пришлось выводить реверсированный список в самой рекурсии, а точнее – в правиле, описывающем условие останова рекурсии.

Добавим в предикат rev ещё один аргумент для того, чтобы передать полученный на дне рекурсии реверсированный список прямо на выход из рекурсии. Третий аргумент при каждом рекурсивном вызове унифицировать сам с собой до тех пор, пока не выполнится условие останова рекурстии.

Пример 9. Реверс списка:

implement main

open core, console

constants

className = "com/visual-prolog/main".

classVersion = "$JustDate: $$Revision: $".

class predicates

reverse : (integer* ВходнойСписок, integer* РеверсСписок, integer* Результат) procedure (i,i,o).

clauses

classInfo(className, classVersion).

reverse([X|L],T,R) :- !,reverse(L,[X|T],R).

reverse(_,R,R).

run():-init(),

   reverse([1,2,3,4,5,6,7,8,9],[],R),

   write(R),

   _=readchar().

end implement main

goal

   mainExe::run(main::run).

В вышеописанном примере видно, что в правиле reverse(_,R,R). Второй аргумент, в котором собран реверс исходного списка, унифицируется с третьим аргументом, через который мы и получим результат на выходе из рекурсии.

Пример 10. Полиморфный реверс списка:

implement main

open core, console

constants

className = "com/visual-prolog/main".

classVersion = "$JustDate: $$Revision: $".

class predicates

reverse : (Elem* ВходнойСписок, Elem* РеверсСписок, Elem* Результат) procedure (i,i,o).

clauses

classInfo(className, classVersion).

reverse([X|L],T,R) :- !,reverse(L,[X|T],R).

reverse(_,R,R).

run():-init(),

   reverse(["123","abc","абв"],[],R),

   write(R),nl,

   reverse([8.2,9.4,10.8],[],R1),

   write(R1),nl,

   _=readchar().

end implement main

goal

   mainExe::run(main::run).

Пример 11. Соединение двух списков:

implement main

open core, console

constants className = "com/visual-prolog/main".

classVersion = "$JustDate: $$Revision: $".

class predicates

append : (Elem* Список1, Elem* Список2, Elem* Результат) procedure (i,i,o).

clauses

classInfo(className, classVersion).

append([X|L1],L2,[X|L]) :- !,append(L1,L2,L).

append(_,L,L).

run():-init(),

   append(["123","abc","абв"],["prolog","пролог"],L),

   write(L),nl,

   append([8.2,9.4,10.8],[-0.999,123.45],L1),

   write(L1),nl,

   _=readchar().

end implement main

goal

   mainExe::run(main::run).

Задача 8. Написать предикат получения списка, составленного из квадратных корней каждого элемента входного списка.

Задача 9. Написать предикат member(Elem,Elem*) истинный тогда, когда элемент Elem принадлежит списку Elem*.

Задача 10. Написать предикат last(Elem,Elem*), возвращающий последний элемент Elem списка Elem*.

Задача 11. Написать предикат nth(Elem,N,Elem*), возвращающий значение N-го элемента Elem списка Elem*.

Задача 12. Написать предикат set(Elem,N,L,L1), возвращающий новый список L1, который образован из входного списка L путём замены в нём значения N-го элемента новым значением Elem.

Задача 13. Написать предикат max(Elem*,Max), который находит максимальный элемент заданного списка.

Задача 14. Разработать функцию, возвращающую сумму всех элементов списка.

Задача 15. Разработать функцию, вычисляющую среднее арифметическое элементов заданного списка чисел.

Задача 16. Разработать функцию, выделяющую из исходного списка подсписок, начиная с элемента с номером N и заканчивая элементом с номером N+K. N и K – аргументы функции.

Задача 17. Разработать функцию, возвращающую 0, если в исходном списке из нулей и единиц, больше нулей, и 1 – в противном случае.

Задача 18. Разработать полиморфный предикат слияние(L1,L2,L3), который производит операцию объединения двух упорядоченных по убыванию списков L1, L2 в третий, упорядоченный по убыванию список L3.

Задача повышенной трудности 1. Написать предикат сортировки sort(L,L1), который сортирует входной список L любым методом сортировки в выходной список L1.

Задача повышенной трудности 2. Дан список координат точек на плоскости, например: [[1,3],[2,5],[3,-8],[1,1],[1,0],[2,-2]]. Необходимо вывести координаты самой ближней к центру координат точки, и самой дальней.

Соседние файлы в папке Лабораторные работы