Negação como falha

Um programa P não pode produzir informação negativa no sentido da negação lógica. De seguida assumimos a ``Hipótese do Mundo Fechado'' (teoria das bases de dados) e vamos produzir informação negativa mas num sentido diferente: substituímos

(i)
``not(A) é consequência lógica de P'' (negação lógica)

por

(ii)
``A não é consequência lógica de P'' (negação como falha)

Para apreciar a diferença entre (i) e (ii), podemos observar que:

Podemos acentuar a diferença entre (i) e (ii) notando que (ii) pode ser escrito como

(ii)
não(A é consequência lógica de P)

Temos usado a designação falha quando um átomo não é unificável com nenhuma cabeça de cláusula. A negação como falha (denotada por not(X) é então definida pelas duas cláusulas seguintes:

         not(X) :- call(X), !, falha.
         not(X).

Uma chamada a not(X), onde X está instanciada por um átomo A, faz com que: se A tiver êxito, então not(A) falha; se A falha em tempo finito, not(A) tem êxito. Na prática temos de assegurar que não existe nenhum facto

         falha.

no nosso programa! Com essa finalidade os interpretadores Prolog têm a constante fail como palavra reservada. Como geralmente os interpretadores de Prolog não efectuam, automaticamente, os retrocessos, para encontrar todas as respostas a uma questão, podemos ``forçar'' esses retrocessos substituindo uma questão

         ?- A.

por uma questão da forma:

         ?- A, "write resposta", fail.

Há todo um conjunto de questões de 'Fundamentos da Lógica' que esta negação como falha levanta. Aqui vamos apenas dar alguns exemplos que mostram que o seu uso é delicado. Consideremos um programa cuja única cláusula é

         igual(X,X).

e sejam a e b duas constantes. Notemos que, segundo a visão procedimental, igual é o procedimento de unificação, uma vez que a chamada igual(A1,A2) tem por efeito unificar A1 a A2. A chamada a not(igual(a,b)) tem êxito:

         ?- not(igual(a,b)).
            yes

enquanto a chamada not(igual(a,a)) falha:

         ?- not(igual(a,a)).
            no

Consideremos agora os alvos seguintes:

         ?- igual(X,a), not(igual(X,b)).
            X = a
            yes
         ?- not(igual(X,b)), igual(X,a).
            no

A segunda questão falha, porque igual(X,b) tem êxito com . Juntemos agora ao programa que fizemos para o Problema 1, das relações de parentesco, as seguintes cláusulas:

         masculino(paulo).
         masculino(gustavo).
         masculino(luis).
         masculino(eusebio).

         igual(X,X).

         irmao(X,Y) :-
           not(igual(X,Y)),
           masculino(X),
           progenitores(P,M,X),
           progenitores(P,M,Y).

na esperança de definir a relação ``é irmão de''. À questão

         ?- irmao(eusebio,ana).

recebemos uma confirmação

         yes

mas já a questão

         ?- irmao(X,ana).

falha:

         no

e portanto não nos dá a resposta

         X = eusebio

Isto acontece porque igual(X,ana) tem êxito com X = ana. O mesmo fenómeno acontece com a questão

         ?- irmao(X,Y).
            no

Mas se definirmos ``é irmão de'' por:

         irmao(X,Y) :-
           masculino(X),
           progenitores(P,M,X),
           progenitores(P,M,Y),
           not(igual(X,Y)).

então teremos

         ?- irmao(eusebio,ana).
            yes

         ?- irmao(X,ana).
            X = eusebio
            yes

         ?- irmao(X,Y).
            X = eusebio, Y = ana
            yes

(c) Delfim F. Marado Torres
1999-04-13