В базе знаний можно хранить динамический встречный предикат, который увеличивается при каждом выполнении основного предиката.Значение счетчика изменяется с assert
и retract
, т. Е. Это не переменная в вашем основном предикате, а глобально сохраненное значение.
В вашем основном предикате, если вы добавляете условие, котороезначение счетчика должно быть больше, чем какое-либо значение пропуска, после чего вы будете принудительно возвращаться к действительным правилам для указанного числа итераций.
В качестве примера рассмотрим встроенный предикат permutation/2
, который вычисляет перестановки списка(примечание: протестировано с использованием SWI-Prolog, другие интерпретаторы имеют разные встроенные предикаты).Пример вывода:
?- permutation([1,2,3,4,5],L).
L = [1, 2, 3, 4, 5] ;
L = [1, 2, 3, 5, 4] ;
L = [1, 2, 4, 3, 5] ;
L = [1, 2, 4, 5, 3] ;
L = [1, 2, 5, 3, 4] ;
L = [1, 2, 5, 4, 3] ;
Если вы хотите пропустить первые 5 итераций в своем запросе, вы можете использовать следующий код:
:- dynamic iteration_nr/1.
iteration_nr(0).
get_permutations(L1,L2,Skip) :-
permutation(L1,L2),
iteration_nr(N),
N2 is N+1,
retract(iteration_nr(N)),
asserta(iteration_nr(N2)),
Skip < N2. % force backtracking here if counter < Skip
Пример вывода:
?- get_permutations([1,2,3,4,5],L2,5).
L2 = [1, 2, 5, 4, 3] ;
L2 = [1, 3, 2, 4, 5] ;
L2 = [1, 3, 2, 5, 4]
Обратите внимание, что здесь используется asserta
(т. Е. Утверждение в начале) вместо простого assert
, которое не рекомендуется.Также обратите внимание, что счетчик сохранит значение, поэтому при повторном запуске этого же сеанса результаты будут другими.Для сброса счетчика вы можете использовать отдельный предикат инициализации, например:
init_and_get_permutations(L1,L2,Skip) :-
retractall(iteration_nr(_)),
asserta(iteration_nr(0)),
get_permutations(L1,L2,Skip).
Примечание: использование assert
и retract
на самом деле не считается «чистым» прологическим программированием, потому что этопроцедурный и меняет базу знаний.Однако для некоторых приложений это может быть полезно.