Estoy buscando una manera de contar el número de predicados. Ejemplo:

%hechos

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

% y pregunto

count_has_subclass(thing,X).

% resultado

X = 3.

1
Higor Gomes 10 may. 2019 a las 22:03

4 respuestas

La mejor respuesta

Podemos usar findall/3 para esto, y luego use {{X1} } para obtener la longitud de la lista:

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

Sin embargo, si es posible que has_subclass/2 produzca los valores mismos varias veces para una clave determinada (como thing), entonces podemos usar, por ejemplo, sort/2 como un filtro duplicado, como:

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

Tenga en cuenta que si What es una variable libre, entonces contará todos los rendimientos de has_subclass(_, _). (opcionalmente con un filtro de unicidad en el segundo parámetro).

1
Willem Van Onsem 10 may. 2019 a las 19:11

El uso del estándar setof/3 es una mejor opción, ya que permite una fácil definición de un predicado más general que puede enumerar soluciones cuando el argumento de clase no está vinculado. Por ejemplo, suponga la siguiente base de datos:

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).

Y la definición:

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

Llamada de muestra:

| ?- subclass_count(Class, Count).

Class = animal
Count = 2 ? ;

Class = thing
Count = 3 ? ;

Class = tree
Count = 2

yes

Si intenta en su lugar una de las soluciones findall/3 en las otras respuestas, obtenemos en su lugar:

| ?- count_has_subclass(What, Count).

Count = 7

Pero tenga en cuenta que esta solución también tiene una interpretación sensata, ya que devuelve el número de todas las subclases existentes cuando no se especifica la clase.

1
Paulo Moura 10 may. 2019 a las 20:11

Para hechos como su ejemplo:

count_has_subclass(What, Count):-
  findall(1, call(has_subclass(What, _)), L),
  length(L, Count).
2
gusbro 10 may. 2019 a las 19:05

Construir una lista solo para contar soluciones parece 'viejo estilo', pero en Prolog tradicional solo existe la alternativa DB (afirmar / retraer) para superar la naturaleza 'sin estado' de los cálculos. De hecho, Findall / 3 y amigos incorporados podrían reescribirse (ingenuamente) por medio de afirmar / retraer. Pero algo ha aparecido desde principios de los 80's :). Ilustraré con SWI-Prolog, pero, más o menos ingenuamente, todos ellos podrían implementarse mediante aserción / retracción. Por supuesto, la mayoría de las implementaciones de Prolog tienen facilidades 'no lógicas' (o 'imperativas' o 'impuras') para implementar dicha tarea básica, sin recurrir a la interfaz DB de peso pesado, como setarg / 3, nb_setval / 2 y otros ...

Me estoy desviando ... la biblioteca (agregado) debe mostrarse primero:

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

Vale la pena estudiar esta biblioteca, hace mucho más que, eficientemente, contar ... Otra adición reciente es la biblioteca (solution_sequences). No es más eficiente que setof / 3 + length / 2, supongo, pero es interesante en sí mismo. El conteo es un poco más complicado y utiliza call_nth / 2 :

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

Algunos código mío más simple, basado en nb_setarg / 3 (y ayuda de @false):

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

?- integrate(count,has_subclass(thing,T),C).
C = 3.
0
CapelliC 15 may. 2019 a las 15:57