
Генерация списков
Генерация списков обычно производится рекурсивно. На каждом витке рекурсивного цикла в список добавляется, как правило, один элемент. Заполнение списка может производиться как слева направо, так и справа налево. Рассмотрим оба варианта на примерах.
Следующий пример показывает заполнение списка, при котором хвост списка, являющийся свободной переменной, передаётся в очередной рекурсивный вызов. При таком способе заполнения список наполняется слева направо, то есть от головы к хвосту.
Пример 1. Генерация списка целых чисел в заданном диапазоне [From..UpTo]:
implement main
open core, console
constants
className = "com/visual-prolog/main".
classVersion = "$JustDate: $$Revision: $".
class predicates
gen : (integer From, integer UpTo, integer* Список) procedure (i,i,o).
clauses
classInfo(className, classVersion).
gen(I,N,[]):-I>N,!. % Условие останова рекурсии
gen(I,N,[I|L]):-gen(I+1,N,L). % Продолжение рекурсии
run():-init(),
gen(1,10,L), % Диапазон от 1 до 10
write(L),
_=readchar().
end implement main
goal
mainExe::run(main::run).
Следующий пример показывает добавление к входному списку целых чисел. При этом весь список, являющийся связанной переменной, передаётся в очередной рекурсивный вызов. При таком способе новый список заполняется справа налево, то есть от хвоста к голове.
Пример 2. Генерация реверсированного списка целых чисел в заданном диапазоне [From..UpTo]:
implement main
open core, console
constants
className = "com/visual-prolog/main".
classVersion = "$JustDate: $$Revision: $".
class predicates
add : (integer From, integer UpTo, integer* ВходнойСписок, integer* ВыходнойСписок) procedure (i,i,i,o).
clauses
classInfo(className, classVersion).
add(I,N,L,L):-I>N,!.
add(I,N,T,L):-add(I+1,N,[I|T],L).
run():-init(),
add(1,10,[],L),
write(L),
_=readchar().
end implement main
goal
mainExe::run(main::run).
Пример 3. Добавление к входному списку ВходнойСписок целых чисел в реверсированном порядке в диапазоне [From..UpTo]:
implement main
open core, console
constants className = "com/visual-prolog/main".
classVersion = "$JustDate: $$Revision: $".
class predicates add : (integer From, integer UpTo, integer* ВходнойСписок, integer* ВыходнойСписок) procedure (i,i,i,o).
clauses
classInfo(className, classVersion).
add(I,N,L,L):-I>N,!.
add(I,N,T,L):-add(I+1,N,[I|T],L).
run():-init(),
add(1,10,[110,120,130],L),
write(L),
_=readchar().
end implement main
goal
mainExe::run(main::run).
Задача 1. Переписать предикат из примера 1 в функциональном стиле:
gen : (integer From, integer UpTo) -> integer* Список.
Задача 2. Переписать предикат из примера 2 в функциональном стиле:
add : (integer From, integer UpTo, integer* ВходнойСписок) -> integer* ВыходнойСписок.
Задача 3. Написать предикат генерации списка первых n нечётных положительных целых чисел.
Задача 4. Написать предикат генерации списка первых n чисел гармонического ряда. Подсказка: n-й член такого ряда равен 1/n.
Задача 5. Написать предикат генерации списка первых n случайных целых чисел. Подсказка: функция, возвращающая случайное число описана в классе math.
Задача 6. Написать предикат генерации списка факториалов от 1! до n!.
Задача 7. Написать предикат генерации списка первых n чисел ряда Фибоначчи. Подсказка: первые два числа ряда Фибоначчи равны единице, каждый очередной элемент равен сумме двух предыдущих. Вот первые шесть чисел ряда Фибоначчи: 1, 1, 2, 3, 5, 8.