Подтвердить что ты не робот

Пролог подсчитывает количество раз, когда предикат является истинным

Я хочу подсчитать количество раз, когда пользовательский предикат является истинным. Например, у меня есть следующий код:

is_man(john).
is_man(alex).
?:-is_man(X).

X вернет john, тогда, если я нажимаю точку с запятой, он также вернет alex, а затем false.

Я хочу создать что-то вроде:

count(is_man(X), Count).

И чтобы вернуться

Count = 2

Как я могу это сделать?

4b9b3361

Ответ 1

В SWI-Prolog:

aggregate_all(count, is_man(X), Count).

Ответ 2

Для стандартного решения Prolog для ISO вы можете использовать findall/3, чтобы составить список всех решений, а затем установить Count на длину результирующего списка. Это может быть несколько сложнее обернуть это в пользовательский предикат count/2, как вы предлагаете, потому что нам нужно сформировать первый аргумент findall/3 в который учитывает любые свободные (несвязанные) переменные в цели, которую вы хотите передать в качестве первого аргумента count/2.

Многие прологи предоставляют "счетчики" или другие формы изменчивых глобальных значений, нестандартное расширение, которое может использоваться в связи с "циклом", вызванным ошибкой, для того, чтобы сделать тот же подсчет. Немного более громоздко, но придерживаться буквы стандарта Prolog было бы использовать assert и retract, чтобы создать свой собственный счетчик, настроив динамический факт.

Далее следует иллюстрация последнего подхода. Чтобы сделать его "многопоточным безопасным", потребуется дополнительная логика.

count(Goal,_) :-
    setGoalCount(0),
    call(Goal),
    incGoalCount(1),
    fail.              /* or false in some Prologs */
count(_,Count) :-
    getGoalCount(Count).

setGoalCount(_) :-
    retract(getGoalCount(_)),
    fail.
setGoalCount(X) :-
    assert(getGoalCount(X)).

incGoalCount(Y) :-
    retract(getGoalCount(X)),
    !,
    Z is X + Y,
    assert(getGoalCount(Z)).

Ответ 3


count(P,Count) :-
        findall(1,P,L),
        length(L,Count).