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.
4 respuestas
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).
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.
Para hechos como su ejemplo:
count_has_subclass(What, Count):-
findall(1, call(has_subclass(What, _)), L),
length(L, Count).
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.
Nuevas preguntas
prolog
No use esta etiqueta como Prólogo y Epílogo. Prolog es el lenguaje de programación lógica más utilizado. Es compatible con la programación no determinista mediante el seguimiento cronológico y la coincidencia de patrones mediante la unificación.