




























































































Estude fácil! Tem muito documento disponível na Docsity
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Prepare-se para as provas
Estude fácil! Tem muito documento disponível na Docsity
Prepare-se para as provas com trabalhos de outros alunos como você, aqui na Docsity
Encontra documentos específicos para os exames da tua universidade
Prepare-se com as videoaulas e exercícios resolvidos criados a partir da grade da sua Universidade
Responda perguntas de provas passadas e avalie sua preparação.
Ganhe pontos para baixar
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
INTRODUÇÃO À PROGRAMAÇÃO PROLOG
Tipologia: Notas de estudo
1 / 198
Esta página não é visível na pré-visualização
Não perca as partes importantes!





























































































Editora da Universidade Católica de Pelotas / UCPEL Rua Félix da Cunha, 412 - Fone (0532)22-1555 - Fax (0532)25- Pelotas - RS - Brasil EDUCAT Editora da Universidade Católica de Pelotas Pelotas, 1997 © 1997 LUIZ A. M. PALAZZO
Adenauer Corrêa Yamin Pelotas, RS
1. LÓGICA E PROGRAMAÇÃO DE COMPUTADORES
A lógica é a ciência do pensamento correto^1. Esta declaração não implica contudo em afirmar que ela seja a ciência da verdade. Mesmo que tudo o que se permita afirmar dentro da lógica seja suposta- mente verdadeiro em determinado contexto, as mesmas afirmações podem resultar falsas se aplicadas ao mundo real. Os filósofos da lógica afirmam que, "para entender o que realmente acontece no mun- do, precisamos entender o que não acontece" , isto é, as propriedades invariantes das entidades ou objetos que o compõem. Com essa idéia em mente, podemos considerar lógicos os conjuntos de de- clarações que possuem a propriedade de ser verdadeiros ou falsos independentemente do tempo ou lugar que ocupam no universo considerado. Este insigth inicial costuma ser de grande valia para en- tender como a lógica pode ser empregada na programação de computadores com grande vantagem sobre as linguagens convencionais. O cálculo proposicional, que é o subconjunto da lógica matemáti- ca mais diretamente envolvido nesse processo, formaliza a estrutura lógica mais elementar do discurso definindo precisamente o significado dos conetivos e, ou, não, se...então e outros. No presente capí- tulo esboça-se a forma como evoluiu a idéia de empregar a lógica como linguagem de programação de computadores, comenta-se os principais usos e aplicações das linguagens baseadas na lógica, relata-se os resultados mais significativos obtidos ao longo dos dez anos do controvertido projeto japonês para o desenvolvimento dos denominados "Computadores de Quinta Geração" e, por fim, se tenta antecipar as perspectivas mais promissoras da pesquisa neste ramo do conhecimento científico.
1.1 AS RAÍZES
O uso da lógica na representação dos processos de raciocínio remonta aos estudos de Boole (1815-
No final do século passado a matemática havia atingido um estágio de desenvolvimento mais do que propício à exploração do novo instrumento proposto por Frege. Os matemáticos estavam abertos a novas áreas de pesquisa que demandavam profundo entendimento lógico assim como procedimentos sistemáticos de prova de teoremas mais poderosos e eficientes do que os até então empregados. Al- guns dos trabalhos mais significativos deste período foram a reconstrução axiomática da geometria abstrata por David Hilbert, a aritimética proposta por Giuseppe Peano e a exploração intuitiva da teo- ria geral dos conjuntos, por Georg Cantor, que também produziu a iluminada teoria dos números transfinitos. O relacionamento entre lógica e matemática foi profundamente investigado por Alfred North Whitehead e Bertrand Russel, que em "Principia Mathematica" (1910) demonstraram ser a ló- gica um instrumento adequado para a representação formal de grande parte da matemática.
Um passo muito importante foi dado em 1930, em estudos simultâneos, porém independentes, reali- zados pelo alemão Kurt Gödel e o francês Jacques Herbrand. Ambos, em suas dissertações de douto- rado, demonstraram que o mecanismo de prova do cálculo de predicados poderia oferecer uma prova formal de toda proposição logicamente verdadeira. O resultado de maior impacto foi entretanto pro- duzido por Gödel, em 1931, com a descoberta do "teorema da incompleteza dos sistemas de formali- zação da aritmética". A prova deste teorema se baseava nos denominados paradoxos de auto- referência (declarações do tipo: "Esta sentença é falsa", que não podem ser provadas nem verdadeiras
(^1) Na realidade, de uma certa classe de pensamento correto.
da execução para ser exercido pelo sistema de programação em lógica utilizado. Em outras palavras, a tarefa do programador passa a ser simplesmente a especificação do problema que deve ser soluciona- do, razão pela qual as linguagens lógicas podem ser vistas simultaneamente como linguagens para especificação formal e linguagens para a programação de computadores.
Um programa em lógica é então a representação de determinado problema ou situação expressa atra- vés de um conjunto finito de um tipo especial de sentenças lógicas denominadas cláusulas. Ao contrá- rio de programas em Pascal ou C, um programa em lógica não é a descrição de um procedimento para se obter a solução de um problema. Na realidade o sistema utilizado no processamento de programas em lógica é inteiramente responsável pelo procedimento a ser adotado na sua execução. Um programa em lógica pode também ser visto alternativamente como uma base de dados, exceto que as bases de dados convencionais descrevem apenas fatos tais como "Oscar é um avestruz", enquanto que as sen- tenças de um programa em lógica possuem um alcance mais genérico, permitindo a representação de regras como em "Todo avestruz é um pássaro", o que não possui correspondência em bases de dados convencionais. Na figura abaixo se procura explicitar as principais diferenças entre programação con- vencional e programação em lógica.
Processamento Numérico Processamento Simbólico Soluções Algorítmicas Soluções Heurísticas Estruturas de Controle e Conhecimento Integradas Estruturas de Controle e Conhecimento Separadas Difícil Modificação Fácil Modificação Somente Respostas Totalmente Corretas Incluem Respostas Parcialmente Corretas Somente a Melhor Solução Possível Incluem Todas as Soluções Possíveis Figura 1.1 Programas Convencionais x Programas em Lógica
O paradigma fundamental da programação em lógica é o da programação declarativa , em oposição à programação procedimental típica das linguagens convencionais. A programação declarativa engloba também a programação funcional, cujo exemplo mais conhecido é a linguagem Lisp. Lembrando en- tretanto que Lisp data de 1960, a programação funcional é um estilo conhecido há bastante tempo, ao contrário da programação em lógica, que só ganhou ímpeto a partir dos anos 80, quando foi escolhida como a linguagem básica do projeto japonês para o desenvolvimento dos denominados computadores de quinta geração. O ponto focal da programação em lógica consiste em identificar a noção de com- putação com a noção de dedução. Mais precisamente, os sistemas de programação em lógica reduzem a execução de programas à pesquisa da refutação das sentenças do programa em conjunto com a ne- gação da sentença que expressa a consulta, seguindo a regra: "uma refutação é a dedução de uma contradição".
Pode-se então expressar conhecimento (programas e/ou dados) em Prolog por meio de cláusulas de
dois tipos: fatos e regras^2. Um fato denota uma verdade incondicional, enquanto que as regras defi- nem as condições que devem ser satisfeitas para que uma certa declaração seja considerada verdadei- ra. Como fatos e regras podem ser utilizados conjuntamente, nenhum componente dedutivo adicional precisa ser utilizado. Além disso, como regras recursivas e não-determinismo são permitidos, os pro- gramadores podem obter descrições muito claras, concisas e não-redundantes da informação que de- sejam representar. Como não há distinção entre argumentos de entrada e de saída, qualquer combina- ção de argumentos pode ser empregada.
Os termos "programação em lógica" e "programação Prolog" tendem a ser empregados indistinta- mente. Deve-se, entretanto, destacar que a linguagem Prolog é apenas uma particular abordagem da programação em lógica. As características mais marcantes dos sistemas de programação em lógica em geral - e da linguagem Prolog em particular - são as seguintes:
(^2) Ver o Apêndice A para uma abordagem mais formal.
A premissa básica da programação em lógica é portanto que "computação é inferência controlada". Tal visão da computação tem se mostrado extremamente produtiva, na medida em que conduz à idéia de que computadores podem ser projetados com a arquitetura de máquinas de inferência. Grande parte da pesquisa sobre computação paralela, conduzida hoje nos EUA, Europa e Japão, emprega a progra- mação em lógica como instrumento básico para a especificação de novas arquiteturas de hardware e o desenvolvimento de máquinas abstratas não-convencionais.
1.3 APLICAÇÕES
Um dos primeiros usos da programação em lógica foi a representação e análise de subconjuntos da linguagem natural. Esta foi inclusive a aplicação que motivou Alain Colmerauer a desenvolver a pri-
tões sobre a estrutura de sentenças em linguagem natural fossem formuladas como objetivos ao sistema, e (3) que diferentes procedimentos de prova aplicados a representações lógicas da lin- guagem natural correspondiam a diferentes estratégias de análise.
Muitas outras aplicações poderiam ainda ser citadas, principalmente na área da inteligência artificial, que tem no Prolog e no Lisp as suas duas linguagens mais importantes. Novas tecnologias de hardwa- re e software tais como sistemas massivamente paralelos, redes de computadores, assistentes inteli- gentes, bases de dados semânticas, etc., tornam o uso do Prolog (e de outras linguagens baseadas em lógica) cada vez mais atraentes
1.4 A QUINTA GERAÇÃO
Em 1979 o governo japonês iniciou estudos para um novo, ambicioso e único projeto na área da com- putação normalmente denominado Sistemas Computacionais de Quinta Geração cujo objetivo princi- pal era o desenvolvimento, no espaço de uma década, de hardware e software de alto desempenho, caracterizando uma nova geração de computadores. O projeto iniciou em 1982 e foi oficialmente en- cerrado em maio de 1992. Muito foi dito e escrito sobre o projeto, que produziu inúmeros resultados e diversos subprodutos ao longo desses dez anos. Um de seus principais méritos, entretanto, parece ter sido chamar a atenção da comunidade científica mundial para as potencialidades da lógica como lin- guagem de programação de computadores. Sistemas de processamento lógico paralelo derivados do Prolog foram desenvolvidos para servir como linguagens-núcleo (kernel languages) dos novos equi- pamentos que seriam produzidos a partir dos resultados do projeto. Considerado um sucesso por seus dirigentes, o projeto foi entretanto criticado por não haver conseguido colocar as tecnologias desen- volvidas à disposição do grande público. Em outras palavras: ainda não dispomos hoje (1994) de mi- crocomputadores pessoais de quinta geração - denominados máquinas PSI (Personal Sequential Infe- rence machines) - comercialmente viáveis para o grande público. Os resultados teóricos obtidos e os protótipos construídos foram entretanto de grande valia para que num futuro próximo isso venha a ser possível. Nestas novas máquinas o papel da linguagem assembly será desempenhado por um dialeto do Prolog orientado ao processamento paralelo.
Um relatório sobre o projeto, organizado por Ehud Shapiro e David Warren em 1993, reuniu as opini- ões de diversos pesquisadores dele participantes, entre os quais Kazuhiro Fuchi, seu líder, Robert Kowalski, Koichi Furukawa, Kazunori Ueda e outros. Todos os depoimentos foram unânimes em
declarar que os objetivos do projeto foram plenamente atingidos. Na Figura 1.2 é mostrada uma adaptação em português do diagrama "de intenções" apresentado por Fuchi, no Fifth Generation Computer Systems Congress de 1981 (FGCS'81), o congresso que deu a conhecer ao mundo um dos mais ambiciosos projetos da história da computação.
ANO 1 ANO 5 ANO 10
Network --- Ótica ---
Personal Inference Machine (Redução a chips)
Máquina Prolog +
(Novo Software) LISPAPL Smalltalk PS, etc.
Programação: em lógica e funcional
(comparáveis às máquinas de grande porte de 1981)
Ambientes de Programação Inteligentes Ambientes de Projeto Orientados à Prototipagem Máquinas Altamente Configuráveis (Chips e Módulos) Supermáquinas (Realmente Inteligentes)
Nova Linguagem
5G Core Language
(INFERENCE MACHINE)
Data Flow Machine
Database Machine
Paralelismo
Associatividade
SOFTWARE -----------> Engenharia de Conhecimento (Acumulação) ---------------------------------------------------------> Engenharia de Software (Teorias Básicas) Pesquisa em Inteligência Artificial
Solução de Problemas: Bases de Conhecimento:
Simbolismo em Alto Nível: Planejamento Programação Prova de Teoremas Jogos
Entendimento da Linguagem Natural Consultas
Figura 1.2 Diagrama Conceitual do Projeto do Computador de Quinta Geração
Segundo o relatório de Shapiro e Warren, um dos primeiros passos do projeto consistiu em definir uma linguagem de programação em lógica que ao mesmo tempo fosse adequada ao paralelismo do hardware e aos requisitos sofisticados especificados para o software. Baseada no Parlog e no Cuncur- rent Prolog, uma equipe de pesquisadores liderada por Kazunori Ueda desenvolveu a linguagem GHC (Guarded Horn Clauses), que deu origem à KL0 (Kernel Language Zero). Um refinamento dessa ver-
são beta^4 , realizado pela equipe de Takashi Chikayama produziu, em 1987, a linguagem KL1. Todos os sub-projetos do FGCS foram revistos para trabalhar com essa linguagem. Em 1988 os primeiros protótipos do computador de quinta geração foram construídos, recebendo o nome genérico de Pa- rallel Inference Machines (PIMs). Tais computadores possuiam arquitetura massivamente paralela e tinham velocidade de processamento calculada em MLIPS (milhões de inferências lógicas por segun- do). Uma dessas máquinas, denominada Multi-PSI foi apresentada com grande sucesso no FGCS'88.
(^4) Uma versão distribuida a grupos selecionados de usuários para teste e depuração.
que, entre outras vantagens:
(1) É de aprendizado muito mais fácil e natural do que as linguagens procedimentais convencio- nais, podendo inclusive ser ministrada a estudantes entre o final do primeiro e o início do se- gundo grau com grande aproveitamento; (2) Implementa com precisão todos os novos modelos surgidos nos últimos anos, inclusive redes neurais, algoritmos genéticos, sociedades de agentes inteligentes, sistemas concorrentes e pa- ralelos; (3) Permite a implementação de extensões, inclusive em nível meta , e a definição precisa de siste- mas reflexivos (essenciais, por exemplo, à robótica); (4) Libera o programador dos problemas associados ao controle de suas rotinas , permitindo-lhe concentrar-se nos aspectos lógicos da situação a representar.
Tem sido observada a tendência de substituição paulatina no mercado de trabalho dos serviços de programação pelos de especificação. Isso ocorre por várias razões, dentre elas porque as especifica- ções podem ser formalmente provadas corretas, o que não ocorre com facilidade nos programas con- vencionais. Essa transição - da arte de programar à ciência de especificar - vem estimulando o apare- cimento de linguagens como o Prolog, que pode ser visto como sendo simultaneamente uma lingua- gem de programação e de especificação (ou, como querem alguns, como uma linguagem de especifi- cações diretamente executáveis em computadores).
Vem também ocorrendo aceleradamente a popularização de ambientes e interfaces cada vez mais próximos do usuário final e oferecendo recursos muito poderosos para a personalização de programas de acordo com as preferências individuais. Isso permite supor que, num futuro próximo, qualquer pessoa, mesmo sem formação específica em programação, poderá interagir facilmente com computa-
dores, em níveis muito elevados^7 , dispensando em grande parte a programação, tal como é hoje co- nhecida. Por outro lado, a construção de tais ambientes ira depender de profissionais bem mais prepa- rados do que um programador em Pascal, por exemplo. Deverão, tais profissionais, possuir um currí- culo muito mais rico, abrangendo a teoria da computação, lógica matemática, álgebra relacional, filo- sofia, arquiteturas concorrentes e paralelas, etc. Serão necessários entretanto em número muito maior do que se imaginava no início dos anos 80, quando essa tendência ainda não se apresentava perfeita- mente delineada, uma vez que praticamente todo software colocado no mercado deverá ser produzido a partir de suas especificações formais.
Um último motivo - não menos importante que os demais já apresentados - deve ainda ser considera- do: A expressividade herdada da lógica torna a linguagem Prolog um instrumento especialmente po- deroso, adequado para a descrição do mundo real com todos os seus contornos, nuances e sutilezas. Nos poucos casos em que a representação se torna mais difícil - na representação temporal, por exem- plo - a flexibilidade do Prolog em aceitar o desenvolvimento de extensões semanticamente precisas e incorporá-las ao seu mecanismo de produção de inferências, remove qualquer impedimento para o seu emprego em virtualmente qualquer área do conhecimento.
RESUMO
(^7) Ao nível da linguagem coloquial falada ou escrita, por exemplo.
pe, na Universidade de Aix-Marseille em 1972. A formalização semântica da programação com cláusulas de Horn é devida a Kowalski (1974) e a especificação do primeiro "standard" - o Prolog de Edimburgo - foi realizada por Warren e Pereira em 1977;
José é o progenitor de Íris, o sistema responde "sim".
?-progenitor(josé, íris). sim
Maria João
José Ana
Júlia Íris
Jorge
Figura 2.1 Uma árvore genealógica
Uma outra questão poderia ser: "Ana é um dos progenitores de Jorge?". Nesse caso o sistema respon- de "não", porque não há nenhuma cláusula no programa que permita deduzir tal fato.
?-progenitor(ana, jorge). não
A questão "Luís é progenitor de Maria?" também obteria a resposta "não" , porque o programa nem sequer conhece alguém com o nome Luís.
?-progenitor(luís, maria). não
Perguntas mais interessantes podem também ser formuladas, por exemplo: "Quem é progenitor de Íris?". Para fazer isso introduz-se uma variável, por exemplo "X" na posição do argumento corres- pondente ao progenitor de Íris. Desta feita o sistema não se limitará a responder "sim" ou "não", mas irá procurar (e informar caso for encontrado) um valor de X que torne a assertiva "X é progenitor de Íris" verdadeira.
?-progenitor(X, íris). X=josé
Da mesma forma a questão "Quem são os filhos de José?" pode ser formulada com a introdução de uma variável na posição do argumento correspondente ao filhos de José. Note que, neste caso, mais de uma resposta verdadeira pode ser encontrada. O sistema irá fornecer a primeira que encontrar e aguardar manifestação por parte do usuário. Se este desejar outras soluções deve digitar um ponto-e- vírgula (;), do contrário digita um ponto (.), o que informa ao sistema que a solução fornecida é sufi- ciente.
?-progenitor(josé, X). X=júlia; X=íris; não
Aqui a última resposta obtida foi "não" significando que todas as soluções válidas já foram forneci- das. Uma questão mais geral para o programa seria: "Quem é progenitor de quem?" ou, com outra formulação: "Encontre X e Y tal que X é progenitor de Y". O sistema, em resposta, irá fornecer (en- quanto se desejar, digitando ";") todos os pares progenitor-filho até que estes se esgotem (quando então responde "não") ou até que se resolva encerrar a apresentação de novas soluções (digitando "."). No exemplo a seguir iremos nos satisfazer com as três primeiras soluções encontradas.
?-progenitor(X, Y).
X=maria Y=josé; X=joão Y=josé; X=joão Y=ana.
Pode-se formular questões ainda mais complicadas ao programa, como "Quem são os avós de Jor- ge?". Como nosso programa não possui diretamente a relação avô , esta consulta precisa ser dividida em duas etapas, como pode ser visto na Figura 2.2. A saber:
(1) Quem é progenitor de Jorge? (Por exemplo, Y) e (2) Quem é progenitor de Y? (Por exemplo, X)
Esta consulta em Prolog é escrita como uma seqüência de duas consultas simples, cuja leitura pode ser: "Encontre X e Y tais que X é progenitor de Y e Y é progenitor de Jorge".
?-progenitor(X, Y), progenitor(Y, jorge). X=josé Y=íris
X
Y
Jorge
progenitor
progenitor
avô
Figura 2.2 A relação avô em função de progenitor
Observe que se mudarmos a ordem das consultas na composição, o significado lógico permanece o mesmo, apesar do resultado ser informado na ordem inversa:
?-progenitor(Y, jorge), progenitor(X, Y). Y=íris X=josé
De modo similar podemos perguntar: "Quem é neto de João?" :
?-progenitor(joão, X), progenitor(X, Y). X=josé Y=júlia; X=josé Y=íris.
Ainda uma outra pergunta poderia ser: "José e Ana possuem algum progenitor em comum?". Nova- mente é necessário decompor a questão em duas etapas, formulando-a alternativamente como: "En- contre um X tal que X seja simultaneamente progenitor de José e Ana".
?-progenitor(X, josé), progenitor(X, ana). X=joão
Por meio dos exemplos apresentados até aqui acredita-se ter sido possível ilustrar os seguintes pontos:
O símbolo ":-" significa "se" e separa a cláusula em conclusão, ou cabeça da cláusula, e condição ou corpo da cláusula, como é mostrado no esquema abaixo. Se a condição expressa pelo corpo da cláu- sula - progenitor (X, Y) - é verdadeira então, segue como conseqüência lógica que a cabeça - filho(Y, X) - também o é. Por outro lado, se não for possível demonstrar que o corpo da cláusula é verdadeiro, o mesmo irá se aplicar à cabeça.
filho(Y, X) :- progenitor(X, Y)
A maioria dos sistemas Prolog, na ausência de caracteres ASCII adequados, emprega o símbolo com- posto ":-" para denotar a implicação "¬". Aqui, por uma questão de clareza, adotaremos este último símbolo, que é o normalmente empregado na programação em lógica com cláusulas definidas.
A utilização das regras pelo sistema Prolog é ilustrada pelo seguinte exemplo: vamos perguntar ao programa se José é filho de Maria:
?-filho(josé, maria).
Não há nenhum fato a esse respeito no programa, portanto a única forma de considerar esta questão é aplicando a regra correspondente. A regra é genérica, no sentido de ser aplicável a quaisquer objetos X e Y. Logo pode ser aplicada a objetos particulares, como josé e maria. Para aplicar a regra, Y será substituído por josé e X por maria. Dizemos que as variáveis X e Y se tornaram instanciadas para:
X=maria e Y=josé
A parte de condição se transformou então no objetivo progenitor(maria, josé). Em seguida o sistema passa a tentar verificar se essa condição é verdadeira. Assim o objetivo inicial, filho(josé, maria) , foi substituído pelo sub-objetivo progenitor(maria, josé). Esse novo objetivo apresenta-se como trivial, uma vez que há um fato no programa estabelecendo exatamente que Maria é um dos progenitores de José. Isso significa que a parte de condição da regra é verdadeira, portanto a parte de conclusão tam- bém é verdadeira e o sistema responde "sim".
Vamos agora adicionar mais algumas relações ao nosso programa. A especificação, por exemplo, da relação mãe entre dois objetos do nosso domínio pode ser escrita baseada na seguinte declaração lógi- ca:
Para todo X e Y X é mãe de Y se X é progenitor de Y e X é feminino.
que, traduzida para Prolog, conduz à seguinte regra:
mãe(X, Y) :- progenitor(X, Y), feminino(X).
onde a vírgula entre as duas condições indica a sua conjunção , significando que, para satisfazer o corpo da regra, ambas as condições devem ser verdadeiras. A relação avô, apresentada anteriormente na Figura 2.2, pode agora ser definida em Prolog por:
avô(X, Z) :- progenitor(X, Y), progenitor(Y, Z).
Neste ponto é interessante comentar alguma coisa sobre o layout dos programas Prolog. Estes podem ser escritos quase que com total liberdade, de modo que podemos inserir espaços e mudar de linha onde e quando melhor nos aprouver. Em geral, porém, desejamos produzir programas de boa aparên- cia, elegantes e sobretudo fáceis de ser lidos. Com essa finalidade, normalmente se prefere escrever a cabeça da cláusula e os objetivos da condição cada um em uma nova linha. Para destacar a conclusão, identamos os objetivos. A cláusula avô, por exemplo, seria escrita:
avô(X, Z) :- progenitor(X, Y), progenitor(Y, Z).
Adicionaremos ainda uma última relação ao nosso programa para exemplificar mais uma particulari- dade da linguagem Prolog. Uma cláusula para a relação irmã se embasaria na seguinte declaração lógica:
Para todo X e Y X é irmã de Y se X e Y possuem um progenitor comum e X é do sexo feminino.
Ou, sob a forma de regra Prolog:
irmã(X, Y) :- progenitor(Z, X), progenitor(Z, Y), feminino(X).
Deve-se atentar para a forma sob a qual o requisito "X e Y possuem um progenitor comum" foi expres- sa. A seguinte formulação lógica foi adotada: "Algum Z deve ser progenitor de X e esse mesmo Z deve também ser progenitor de Y". Uma forma alternativa, porém menos elegante, de representar a mesma condição seria: "Z1 é progenitor de X e Z2 é progenitor de Y e Z1 é igual a Z2". Se consultarmos o sistema com "Júlia é irmã de Íris?" , obteremos, como é esperado, um "sim" como resposta. Podería- mos então concluir que a relação irmã , conforme anteriormente definida, funciona corretamente, en- tretanto, há uma falha muito sutil que se revela quando perguntamos: "Quem é irmã de Íris?". O sis- tema irá nos fornecer duas respostas:
?-irmã(X, íris). X=júlia; X=íris
dando a entender que Íris é irmã de si própria. Isso não é certamente o que se tinha em mente na defi- nição de irmã , entretanto, de acordo com a regra formulada, a resposta obtida pelo sistema é perfeita- mente lógica. Nossa regra sobre irmãs não menciona que X e Y não devem ser os mesmos para que X seja irmã de Y. Como isso não foi requerido, o sistema, com toda razão, assume que X e Y podem denotar a mesma pessoa e irá achar que toda pessoa do sexo feminino que possui um progenitor é irmã de si própria.
Para corrigir esta distorção é necessário acrescentar a condição de que X e Y devem ser diferentes. Isso pode ser feito de diversas maneiras, conforme se verá mais adiante. Por enquanto vamos assumir que uma relação diferente(X, Y) seja reconhecida pelo sistema como verdadeira se e somente se X e Y não forem iguais. A regra para a relação irmã fica então definida por:
irmã(X, Y) :- progenitor(Z, X), progenitor(Z,Y), feminino(X), diferente(X, Y).
Os pontos mais importantes vistos na presente seção foram: