Как считать предикаты - PullRequest
1 голос
/ 10 мая 2019

Я ищу способ подсчета количества предикатов. Пример:

% факты

has_subclass(thing,animal).
has_subclass(thing,tree).
has_subclass(thing,object).

% и я спрашиваю

count_has_subclass(thing,X).

% результат

X = 3.

Ответы [ 4 ]

2 голосов
/ 10 мая 2019

Для фактов, подобных вашему примеру:

count_has_subclass(What, Count):-
  findall(1, call(has_subclass(What, _)), L),
  length(L, Count).
1 голос
/ 10 мая 2019

Использование стандарта setof/3 является лучшим вариантом, поскольку позволяет легко определить более общий предикат, который может перечислять решения, когда аргумент класса не связан. Например, предположим, что следующая база данных:

has_subclass(thing,animal).
has_subclass(thing,tree).
has_subclass(thing,object).

has_subclass(animal,cat).
has_subclass(animal,dog).

has_subclass(tree,pine).
has_subclass(tree,oak).

И определение:

subclass_count(Class, Count) :-
    setof(Subclass, has_subclass(Class, Subclass), Subclasses),
    length(Subclasses, Count).

Пример звонка:

| ?- subclass_count(Class, Count).

Class = animal
Count = 2 ? ;

Class = thing
Count = 3 ? ;

Class = tree
Count = 2

yes

Если вы попробуете вместо одного из findall/3 решений в других ответах, вместо этого мы получим:

| ?- count_has_subclass(What, Count).

Count = 7

Но обратите внимание, что это решение также имеет разумную интерпретацию как возвращение числа всех существующих подклассов, когда класс не указан.

1 голос
/ 10 мая 2019

Мы можем использовать findall/3 для этого, а затем использовать length/2, чтобы получить длину списка:

count_has_subclass(What, N):-
    findall(X, has_subclass(What, X), L),
    length(L, N).

Если, однако, возможно, что has_subclass/2 даст несколько раз одинаковых значений для данного ключа (например, thing), то мы можем использовать, например, sort/2 в качестве дублирующего фильтра, например:

count_has_subclass(What, N):-
    findall(X, has_subclass(What, X), L),
    <b>sort(L, S),</b>  %% remove duplicates
    length(S, N).

Обратите внимание, что если What является свободной переменной, то вы будете считать все результаты has_subclass(_, _). (опционально с фильтром уникальности по второму параметру).

0 голосов
/ 15 мая 2019

Создание списка только для подсчета решений кажется «старым стилем», но в традиционном Прологе есть только альтернатива БД (утверждение / удаление) для преодоления «вычислений без сохранения состояния».В самом деле, buildall / 3 и встроенные друзья могут быть (наивно) переписаны с помощью assert / retract.Но кое-что появилось с начала 80-х годов :).Я проиллюстрирую это с помощью SWI-Prolog, но - более или менее наивно - все они могут быть реализованы с помощью assert / retract.Конечно, большинство реализаций Пролога имеют «нелогичные» (или «императивные», или «нечистые») средства для реализации такой основной задачи, не прибегая к более тяжелому интерфейсу БД - как setarg / 3, nb_setval / 2 и другие ...

Я отвлекся ... библиотека ( агрегат ) должна быть показана первой:

?- aggregate(count, T^has_subclass(thing,T), C).
C = 3.

Эта библиотекаСтоит учиться, гораздо больше - эффективно - считать ... Еще одно недавнее добавление - библиотека ( solution_sequence ).Это не более эффективно, чем setof / 3 + length / 2, думаю, но интересно само по себе.Подсчет немного сложнее и использует call_nth / 2:

?- order_by([desc(C)],call_nth(has_subclass(thing,T),C)).
C = 3,
T = object ;
...

Какой-то гораздо более простой мой код , основанный на nb_setarg / 3 (и справка от @false):

?- [carlo(snippets/lag)].
true.

?- integrate(count,has_subclass(thing,T),C).
C = 3.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...