Посчитать количество вызовов пункта
У меня есть пункт вроде следующего:
lock_open: - conditional_combination (Х), равным (X,[8,6,5,3,6,9]),!, печать (X).
этот пункт успешен. Но я хочу знать, сколько раз вызывается conditional_combination() equal(X,[8,6,5,3,6,9])
стало правдой. программа должна генерировать перестановку, следуя некоторым правилам. И мне нужно, сколько перестановок нужно сгенерировать, чтобы получить конкретное значение, например 865369.
2 ответа
То, что вы на самом деле хотите, - это что-то немного другое: вы хотите посчитать количество ответов (пока) цели.
Следующий предикат call_nth(Goal_0, Nth)
преуспевает как call(Goal_0)
но имеет дополнительный аргумент, который указывает, что найденный ответ является n-ным ответом. Это определение очень специфично для SWI или YAP. Не используйте такие вещи, как nb_setarg/3
в ваших общих программах, но используйте их для хорошо инкапсулированных случаев, как этот. Даже в этих двух системах точное значение этих конструкций недостаточно определено для общего случая. Вот определение для SICStus.
call_nth (цель_0, C):- State = count(0,_), % обратите внимание на дополнительный аргумент, который остается переменной Goal_0, arg(1, State, C1), С2 представляет собой С1+1, nb_setarg(1, штат, C2), С = С2.
Более надежная абстракция обеспечивается Eclipse:
call_nth(Goal_0, Nth) :-
shelf_create(counter(0), CounterRef),
call(Goal_0),
shelf_inc(CounterRef, 1),
shelf_get(CounterRef, 1, Nth).
? - call_nth (между (1,5, I), Nth). I = Nth, Nth = 1; I = Nth, Nth = 2; I = Nth, Nth = 3; I = Nth, Nth = 4; I = Nth, Nth = 5.
Так что просто оберните это вокруг:
lock_open: - call_nth (условная_комбинация (X), Nth), Х = [8,6,5,3,6,9],!, ....
Если вы используете пролог SWI, вы можете использовать nb_getval/2
а также nb_setval/2
добиться того, что вы хотите:
lock_open:-
nb_setval(ctr, 0), % Initialize counter
conditional_combination(X),
nb_inc(ctr), % Increment Counter
equal(X,[8,6,5,3,6,9]),
% Here you can access counter value with nb_getval(ctr, Value)
!,
print(X).
nb_inc(Key):-
nb_getval(Key, Old),
succ(Old, New),
nb_setval(Key, New).
Другие прологи имеют другие способы сделать то же самое, ищите глобальные переменные в вашей реализации пролога. В этом фрагменте я использовал термин ctr
держать текущий счетчик цели. Вы можете использовать любой термин, который не используется в вашей программе.
Работая над модулем "микро", я недавно изобрел опорные точки. Они вдохновлены шаблоном потока / канала для передачи данных. Pivot - это ограниченная очередь максимальной длины, pivot_put/1 также копирует данный термин. Но по соображениям производительности они не используют синхронизированные и не блокируют.
Насколько они очень похожи на nb_setarg/3, за исключением того, что они не разрушают термин Prolog, а вместо этого обновляют структуру данных Java. В результате они немного более безопасны, чем нелогичные операции с терминами. Также им не нужен call_cleanup/3, так как они являются сборщиком мусора Java.
В той степени, в которой они более похожи, чем nb_setarg/3, чем использование некоторого явного выделения и освобождения структур. Так, например, решение для SICStus Prolog может быть:
call_nth(Goal_0, Nth) :-
new(unsigned_32, Counter),
call_cleanup(call_nth1(Goal_0, Counter, Nth),
dispose(Counter)).
call_nth1(Goal_0, Counter, Nth) :-
call(Goal_0),
get_contents(Counter, contents, Count0),
Count1 is Count0+1,
put_contents(Counter, contents, Count1),
Nth = Count1.
С опорными точками нет даже 32-битного ограничения, и мы можем напрямую сделать:
call_nth(G, C) :-
pivot_new(P),
pivot_put(P, 0),
call(G),
pivot_take(P, M),
N is M+1,
pivot_put(P, N),
C = N.