Disciplina: Lógica Aplicada à Computação Nome: Matrícula: 1. Considere a seguinte base de conhecimentos Prolog: filho(paulo,pedro). % "Paulo é filho de Pedro" filho(paulo,marcela). filho(pedro,josé). filho(pedro,isabel). filho(josé,luiz). filho(josé,ana). filho(tiago,luiz). filho(tiago,gabriela). filha(lúcia,ana). % "Lúcia é filha de Ana" filha(lúcia,luiz). filha(carol,luiz). filha(carol,fernanda). filha(isabel,jo~ao). filha(isabel,fernanda). filha(maria,luiz). filha(maria,gabriela). sexo(marcela, feminino ). % "Marcela é do sexo feminino" sexo(ana, feminino ). sexo(fernanda, feminino ). sexo(gabriela, feminino ). sexo(luiz, masculino ). sexo(jo~ao, masculino ). Estenda esta base de conhecimentos acrescentando regras para os predicados irm~aos/2 (filhos de pelo menos um progenitor comum, qualquer que seja o sexo), tiaavó/2 (irmã de um dos avós) e trifamília/3 (dois homens e uma mulher, onde a mulher tem filhos com cada um dos homens, ou duas mulheres e um homem, onde o homem tem filhos com cada uma das mulheres). Escreva sempre um comentário com o significado de cada novo predicado introduzido. Nota. Você pode estender os predicados primitivos da base de conhecimentos acima, caso necessite, mas somente pela adição de novas regras, nunca de novos fatos. Você também pode utilizar predicados auxiliares para facilitar a tarefa acima mas não poderá se referir a eles nas tarefas abaixo.
Soluções. % regras para a relaç~ao irm~aos/2 % (filhos, de qualquer sexo, com pelo menos um progenitor em comum) % predicado auxiliar, que será usado aqui e novamente logo adiante: filhoa(x,y) :- filho(x,y). % "X é filho ou filha de Y" filhoa(x,y) :- filha(x,y). % definiç~ao principal irm~aos(x,y) :- filhoa(x,z), % "X é irm~ao ou irm~a de Y" filhoa(y,z), X \== Y. % para usar tiaavó/2 (irm~a de um dos avós) de forma a cobrir % toda a base de conhecimento, devemos antes de mais nada estender % o predicado primitivo sexo/2 pela adiç~ao de novas regras: sexo(x, masculino ) :- filho(x,_). %"X é do sexo masculino" sexo(x, feminino ) :- filha(x,_). % um predicado auxiliar que pode ser útil adiante é o seguinte: netoa(u,v) :- filhoa(u,z), % "U é neto ou neta de V" filhoa(z,v). % definiç~ao principal tiaavó(x,y) :- netoa(y,w), % "X é tia-avó de Y" irm~aos(w,x), sexo(x, feminino ). % regras para trifamília/3 % (dois homens e uma mulher, onde a mulher tem filhos com cada um dos homens, % ou duas mulheres e um homem, onde o homem tem filhos com cada uma das mulheres) % predicado auxiliar: filhocasal(t,u,v) :- filhoa(t,u), "T é filho ou filha da m~ae U com o pai V" filhoa(t,v), sexo(u, feminino ), sexo(v, masculino ). % definiç~ao principal trifamília(x,y,z) :- filhocasal(_,z,x), "X e Y t^em filhos em comum com Z" filhocasal(_,z,y), X \== Y. trifamília(x,y,z) :- filhocasal(_,x,z), filhocasal(_,y,z), X \== Y. Prof. João Marcos 2
Em seguida, formule as seguintes consultas à base de conhecimentos, usando somente os predicados supra-mencionados de forma explícita (sejam eles primitivos, definidos ou estendidos ao longo da solução da tarefa anterior): (a) Quais são os filhos de Luiz ou de João que não são filhos de Fernanda? (b) Quem é a avó paterna de Paulo? (c) Paulo tem tias-avós por parte de pai? Em caso afirmativo, quem são elas? (d) Quais são os irmãos dos irmãos de Tiago que são eles próprios irmãos de Tiago? Apresente todas as respostas relevantes, na mesma ordem mas sem repetição, que o compilador Prolog daria a cada uma destas consultas. Soluções. (a)?- (filho(x,luiz);filha(x,luiz);filho(x,jo~ao);filha(x,jo~ao)), not(filho(x,fernanda);filha(x,fernanda)). X = josé ; X = tiago ; X = lúcia ; X = maria ; false. Nota: observe que puramente a partir da sintaxe não temos por que concluir que Paulo seria do sexo masculino e que não poderia portanto ser filha de ninguém de fato, tudo que sabemos sobre o significado da string filha é o que a base de conhecimentos nos informa; a interpretação pretendida desta string como um predicado é sempre algo extra-linguístico, e alheio assim ao campo de conhecimento do compilador Prolog. (b)?- (filho(paulo,x) ; filha(paulo,x)), sexo(x, masculino ), filho(x,y), sexo(y, feminino ). X = pedro Y = isabel ; false. Nota: a resposta procurada é o termo atribuído a Y. (c)?- tiaavó(_,paulo). true.?- setof(x,tiaavó(x,paulo),z). Z = [carol, lúcia, maria]. (d)?- irm~aos(x,tiago),irm~aos(x,y),irm~aos(y,tiago). Y = lúcia ; Y = carol ; Y = maria ; Y = josé ; false. Nota: fica excluída assim Isabel, que é irmã de Carol, uma das irmãs de Tiago... Com efeito, a relação de irmandade não é transitiva. Prof. João Marcos 3
No caso da consulta (b) acima, apresente em detalhe o procedimento de resolução usado pelo compilador na obtenção da resposta. Solução. A consulta que fizemos foi a seguinte: :- (filho(paulo,x);filha(paulo,x)), sexo(x, masculino ), filho(x,y), sexo(y, feminino ). Note que esta consulta inicial, que contém uma disjunção, é equivalente em Prolog às duas consultas seguintes, nesta ordem: :- filho(paulo,x), sexo(x, masculino ), filho(x,y), sexo(y, feminino ). :- filha(paulo,x), sexo(x, masculino ), filho(x,y), sexo(y, feminino ). Mostraremos assim o processo de resolução para estas duas cláusulas. Começamos o processo percorrendo a base de conhecimentos da esquerda para a direita e de cima para baixo, buscando alguma regra (ou fato) cuja cabeça contenha uma expressão que unifique com o literal filho(paulo,x). Daí, segue o [Passo 1]: :- filho(paulo,x), sexo(x, masculino ), filho(x,y), sexo(y, feminino ). filho(paulo,pedro). σ 1 = [X pedro] :- filho(paulo,pedro), sexo(pedro, masculino ), filho(pedro,y), sexo(y, feminino ). filho(paulo,pedro). :- sexo(pedro, masculino ), filho(pedro,y), sexo(y, feminino ). Em seguida, buscaremos na base de conhecimentos alguma regra (ou fato) cuja cabeça unifique com o literal sexo(pedro, masculino ). A tarefa terminaria neste ponto se não tivéssemos estendido o predicado primitivo sexo de modo a obter respostas completas para o predicado tiaavó/2, na primeira tarefa acima. Nestas condições, temos então o seguinte [Passo 1.1]: :- sexo(pedro, masculino ), filho(pedro,y), sexo(y, feminino ). sexo(x1, masculino ) :- filho(x1, ). σ 1.1 = [X1 pedro] :- sexo(pedro, masculino ), filho(pedro,y), sexo(y, feminino ). sexo(pedro, masculino ) :- filho(pedro, ). :- filho(pedro,y), sexo(y, feminino ), filho(pedro, ). Continuando, no [Passo 1.1.1]: :- filho(pedro,y), sexo(y, feminino ), filho(pedro, ). filho(pedro,josé). σ 1.1.1 = [Y josé] :- filho(pedro,josé), sexo(josé, feminino ), filho(pedro, ). filho(pedro,josé). :- sexo(josé, feminino ), filho(pedro, ). Prof. João Marcos 4
Seguimos no [Passo 1.1.1.1]: :- sexo(josé, feminino ), filho(pedro, ). sexo(x2, feminino ) :- filha(x2, ). σ 1.1.1.1 = [X2 josé] :- sexo(josé, feminino ), filho(pedro, ). sexo(josé, feminino ) :- filha(josé, ). :- filho(pedro, ), filha(josé, ). :- filho(pedro, ), filha(josé, ). filho(pedro,josé). :- filha(josé, ). :- filha(josé, ). fail Os passos seguintes, 1.1.1.1.1 e 1.1.1.1.1.1, envolvem variáveis anônimas, para as quais não há unificação envolvida, mas apenas uma resposta booleana determinística do Prolog: Como a avaliação da consulta acima não foi bem sucedida em eliminar todos os literais, dadas as regras e unificações escolhidas, força-se um backtracking até o último ponto em que houve uma escolha, a saber, a unificação σ 1.1.1.1. Como não há nova opção de escolha, neste ponto, o backtracking continua até o [Passo 1.1.1.1], e aqui também não há nova opção de escolha. Backtrackings até a unificação σ 1.1.1 e em seguida ao correspondente [Passo 1.1.1] que nos dá finalmente uma opção, que chamaremos de [Passo 1.1.2]: :- filho(pedro,y), sexo(y, feminino ), filho(pedro, ). filho(pedro,isabel). σ 1.1.2 = [Y isabel] :- filho(pedro,isabel), sexo(isabel, feminino ), filho(pedro, ). filho(pedro,isabel). :- sexo(isabel, feminino ), filho(pedro, ). Continuamos agora pelo [Passo 1.1.2.1]: :- sexo(isabel, feminino ), filho(pedro, ). sexo(x3, feminino ) :- filha(x3, ). σ 1.1.2.1 = [X3 isabel] :- sexo(isabel, feminino ), filho(pedro, ). sexo(isabel, feminino ) :- filha(isabel, ). filho(pedro, ), filha(isabel, ). Daí seguem, deterministicamente, de forma abreviada, os seguintes passos 1.1.2.1.1 e 1.1.2.1.1.1: filho(pedro, ), filha(isabel, ). filho(pedro,isabel). filha(isabel, ). filha(isabel,jo~ao). Prof. João Marcos 5
Atingimos assim por fim à cláusula vazia. Conclusão do [Passo 1.1.2.1.1.1], com relação à consulta original: X = pedro Y = isabel Forçando agora um backtracking para obter outras eventuais respostas à consulta original, retornamos sucessivamente à unificação σ 1.1.2.1, à regra escolhida no [Passo 1.1.2.1], à unificação σ 1.1.2, ao literal escolhido no [Passo 1.1.2], à unificação σ 1.1, à regra escolhida no [Passo 1.1], à unificação σ 1 e ao literal escolhido no [Passo 1]. Como todos estes backtrackings falham, acabamos retornando portanto à segunda regra de nossa consulta original, naquele que poderíamos denominar [Passo 2]: :- filha(paulo,x), sexo(x, masculino ), filho(x,y), sexo(y, feminino ). :- filha(paulo,x), sexo(x, masculino ), filho(x,y), sexo(y, feminino ). fail A nova avaliação não é bem-sucedida pois não há expressão que unifique com o literal filha(paulo,x). Logo, não há essencialmente novas respostas à consulta original (a rigor, o Prolog apresentará outras vezes a mesma resposta anterior, antes de falhar) senão aquela já exibida ao fim do [Passo 1.1.2.1.1.1]. Prof. João Marcos 6