Aula 12

Livro texto

Prolog interativo

Continuando prolog basico

vamos assumir o banco de dados

parent(alberto,beatriz).
parent(alberto,carlos).
parent(alberto,zeca).
parent(denise,beatriz).
parent(denise,zeca).
parent(elisa,carlos).
parent(beatriz,flavio).
parent(gustavo,flavio).

a primeira definição de (meio) irmao - pelo menos um parent em comum (neste caso o Z).

     irmao(X,Y) :- parent(Z,X),parent(Z,Y).

testando

      ?- irmao(beatriz,K).

respostas

K = beatriz
K = carlos
K = zeca

beatriz é meio irmã de beatriz? Sim segundo a definição, mas claramente queremos pessoas diferentes.

o =

a operação = em prolog é a operação de unificação que dicutimos ate agora

pedro = antonio      -> falha
X = antonio          -> da certo e X passa a valer  antonio
antonio = X          ->  da certo e X passa a valer antonio
antonio = X, X = Y   -> da certo e X e Y valem anotonio
X = Y                -> da certo e X e Y terao o mesmo valor (quando um assumir um )
X = Y, Y = antonio, X = pedro   -> falha

unificação é uma mistura de teste de igualdade e atribuição (bidirecional)

o not +

Negaçao em prolog é complicada pois não há boleanos. Um predicado nao retorna True, e um not não transforma esse valor para False.

Negação em prolog indica se o predicado de dentro deu ou não certo. negation by failure

       not p(..)     ou \+ p(..)  
       

vai dar certo, se p(...) falhar

       \+ ( p(..), q(..) )

vai dar certo se (p(..),q(..) ) falhar

irmao

     irmao(X,Y) :- parent(Z,X), parent(Z,Y), \+ X=Y.
     

irmao cheio

        irmao_cheio(X,Y) :- parent(Pai,X), parent(Pai,Y),
                            parent(Mae,X), parent(Mae,Y),
                            \+ Mae = Pai,
                            \+ X=Y.

Avô

dado o predicados pai(a,b) se a é pai de b, e mae(a,b)

      avo(A,N) :- pai(A,Mae), mae(Mae,N).
      avo(A,N) :- pai(A,Pai), pai(Pai,N).

duas regras.

o ; ou

o ; é o operador ou.

   a(..), b(..), ( c(..) ; d(..) ).
   

vai tentar provar a depois b e depois c .

Se c falhar, ele vai tentar d antes de dar o backtraking.

Avo pode ser escrito com o ;

     avo(A,N) :- pai(Avo,X), ( mae(X,N) ; pai(X,N) ).

Descendente https://en.wikibooks.org/wiki/Prolog/Recursive_Rules

      descende(X,Ansestral) :- parent(Ansestral,X).
      descende(X,Ansestral) :- parent(Ansestral, Filho), descende(X,Filho).

Coloque o caso base antes.

o caso recursivo tambem poderia ser escrito como

      descende(X,Ansestral) :- parent(PAI, X), descende(PAI,Ansestral).

mas evite colocar a predicado recursivo antes

    NAO FACA
      descende(X,Ansestral) :- descende(PAI,Ansestral), parent(PAI, X),

próxima aula: números e listas. Ai vamos começar a fazer coisas “mais parecidas com programas tradicionais”

Exercícios

suponha que nos temos um predicado v(v1) que indica que v1 é um vertice num grafo e a(v1,v2) que indica que há uma aresta direcionada de v1 para v2

Implemente:

Voce poderá se sentir tentado a descrever alguns/todos algoritmos em grafos como expressões em lógica. Por exemplo, a existencia de um caminho entre 2 vertices é um predicado recursivo. Um grafo é conexo se existe um caminho entre todos os pares de vertices (para grafos não-direcionados), e isso pode ser escrito como um predicado em prolog (usando a dupla negação acima). Mas isso é um erro. Algoritimos em grafos sao inteligentes para se lembrar de tudo que podem a cada visita a um vertice. O prolog “nao se lembra de nada” que ele ja fez. Verificar que nao existe um caminho entre v1 e v2 significa tentar todas as possibilidades, que torna o problema exponencial.