Conjunto de respostas

De Augusto Baffa Wiki
Ir para navegação Ir para pesquisar

Prolog tem três predicados integrados projetados para coletar objetos resultantes de cálculos bem-sucedidos:

bagof(Things, GoalCondition, Bag)
setof(Things, GoalCondition, Bag)
findall(Things,GoalCondition, Bag)

Para ilustrar as diferenças, considere um pequeno exemplo:

listing(p).

p(1,3,5).
p(2,4,1).
p(3,5,2).
p(4,3,1).
p(5,2,4).

Experimente os seguintes objetivos. (As respostas exibidas foram modificadas para economizar espaço.)

?- bagof(Z,p(X,Y,Z),Bag).
Z = _G182 X = 1 Y = 3 Bag = [5] ;
Z = _G182 X = 2 Y = 4 Bag = [1] ;
Z = _G182 X = 3 Y = 5 Bag = [2] ;
Z = _G182 X = 4 Y = 3 Bag = [1] ;
Z = _G182 X = 5 Y = 2 Bag = [4] ;
No

?- findall(Z,p(X,Y,Z),Bag).
Z = _G182 X = _G180 Y = _G181 Bag = [5, 1, 2, 1, 4] ;
No

?- bagof(Z,X^Y^p(X,Y,Z),Bag).
Z = _G182 X = _G180 Y = _G181 Bag = [5, 1, 2, 1, 4] ;
No

?- setof(Z,X^Y^p(X,Y,Z),Bag).
Z = _G182 X = _G180 Y = _G181 Bag = [1, 2, 4, 5] ;
No

Os predicados 'bagof' e 'setof' produzem coleções para ligações individuais das variáveis livres no objetivo. 'setof' produz uma versão classificada da coleção sem duplicatas. Para evitar variáveis de ligação, use uma expressão quantificadora existencial. Por exemplo, o objetivo bagof(Z,X^Y^p(X,Y,Z),Bag) pede "o Bag de Z's tal que existe um X e existe um Y tal que p(X,Y,Z)". 'findall' atua como 'bagof' com todas as variáveis livres automaticamente quantificadas existencialmente. Além disso, 'findall' retorna uma lista vazia [] quando não há satisfação do objetivo, enquanto 'bagof' falha.

?- bagof(Z,(p(X,Y,Z),Z>5),Bag).
No

?- findall(Z,(p(X,Y,Z),Z>5),Bag).
Z = _G182 X = _G180 Y = _G181 Bag = [] 
Yes

Considere outro exemplo. Na seção 2.5, o predicado 'height' foi definido como...

height(Node,H) :- setof(Z,ht(Node,Z),Set),
                  max(Set,0,H).

O cálculo 'setof' reúne todos os Zs que resultam dos cálculos 'ht(Node,Z)' e lista os Zs distintos (diferentes) em Conjunto. Por exemplo,

?- setof(Z,ht(a,Z,Set).
Set=[3,4,2,]

?- setof(Z,ht(a,Z),Set), max(Set,0,H).
Set=[3,4,2] H=4

onde Set = [3,4,2] representa resultados individuais de cálculos 'ht' de 'a' acima de seus descendentes de folhas, mas a altura de 'a' é H = 4. O leitor terá que voltar à seção 2.5 para as definições envolvendo 'ht'. Compare isso com:

?- bagof(Z,ht(a,Z),Bag).
Bag=[3,3,4,2,3,3,3,3,3,3]

O predicado 'findall' pode ser simulado da seguinte forma:

find-all(X,Goal,Bag) :-   post_it(X,Goal),
                          gather([],Bag).

post_it(X,Goal) :- call(Goal),          /* try Goal */
                   asserta(data999(X)), /* assert above others */
                   fail.                /* force backtracking   */
post_it(_,_).                           /* gratuitous success    */

gather(B,Bag) :-  data999(X),          /* find next recorded solution  */
                  retract(data999(X)), /* erase posting       */
                  gather([X|B],Bag),   /* continue  ...        */
                  !.                   /* cut off rule below */
gather(S,S).                           /* when done          */

O leitor deve gastar algum tempo com essas definições. A definição de 'find-all' requer que primeiro todas as respostas sejam postadas na memória usando 'asserta'. Tente vários objetivos 'asserta(p(Constant))', onde 'Constant' tem vários valores constantes como 'a', 'b', etc., cada um seguido respectivamente por um objetivo 'listing(p)' para ver como o Prolog registra a regra. Veja também as definições de 'assert', 'asserta', 'assertz' e 'retract' na seção 4.9. Em segundo lugar, 'find-all' reúne todos os valores postados em uma lista.


Exercício 2.12.1 Modifique a simulação 'findall' fornecida em 'find-all' acima para criar uma versão que não adiciona duplicatas. Use 'assert' e 'retract' de maneiras semelhantes, mas certifique-se de que 'gather' apenas reúna Xs únicos que não foram coletados anteriormente.


Veja Também