Exercícios Práticos com Regras em Prolog

filósofo

Árvore Genealógica — do zero à regras complexas

Neste post vamos construir uma base de conhecimento genealógica completa e definir diversas relações usando regras. O exercício é baseado na árvore genealógica da Figura 1.2 do livro-texto, que descreve três gerações de uma família.

1. A Árvore Genealógica

A figura apresenta a seguinte estrutura familiar (nomes fictícios):

avô João e avó Maria ├── pai Carlos e mãe Ana │ ├── filho Pedro │ ├── filha Clara │ └── filho Lucas └── tia Beatriz e tio Roberto ├── primo João Jr. └── prima Sofia

Relações de parentesco (pai/mãe):

  • João é pai de Carlos e Beatriz.
  • Maria é mãe de Carlos e Beatriz.
  • Carlos é pai de Pedro, Clara e Lucas.
  • Ana é mãe de Pedro, Clara e Lucas.
  • Beatriz é mãe de João Jr. e Sofia.
  • Roberto é pai de João Jr. e Sofia.

📝 2. Definindo os Fatos Básicos

Exercício 1: Crie um arquivo familia.pl e defina os fatos pai/2 e mae/2 com base na árvore acima.

Sua vez: Escreva os fatos no Prolog. Depois, carregue o arquivo e teste as consultas:

?- pai(joao, carlos). → deve retornar true.
?- mae(ana, pedro). → deve retornar true.
?- pai(X, pedro). → deve listar X = carlos.

Solução:

⚧️ 3. Adicionando homem/1 e mulher/1

Exercício 2: Para definirmos relações como “filho” e “filha”, precisamos saber o gênero de cada pessoa. Adicione os fatos homem/1 e mulher/1.

Sua vez: Liste todos os homens e mulheres da árvore.

?- homem(pedro).true
?- mulher(clara).true
?- homem(X). → deve listar todos os homens.

Solução:

4. Regra gerou/2

Exercício 3: Defina a regra gerou(X, Y) que é verdadeira se X é pai ou mãe de Y.

Sua vez: Crie a regra gerou/2 usando os fatos já definidos.

?- gerou(maria, carlos).true
?- gerou(carlos, lucas).true
?- gerou(X, pedro). → deve listar X = carlos e X = ana.

Solução:

A regra usa dois cláusulas (ou é pai ou é mãe). O Prolog tenta a primeira, se falhar, tenta a segunda.

5. Desafios — Definindo Relações Derivadas

Agora vamos construir relações mais complexas. Para cada uma:

  1. Desenhe o grafo de relacionamento (nós = pessoas, arcos = relações).
  2. Codifique a regra em Prolog.
  3. Teste com as consultas sugeridas.

a) filho/2 e filha/2

Grafo para filho/2: pai(X, Y) → Y é descendente mae(X, Y) → Y é descendente homem(Y) → Y é do sexo masculino Exemplo: Carlos → (pai) → Pedro Carlos → (pai) → Lucas Ana → (mae) → Pedro Ana → (mae) → Lucas e Y é homem (pedro, lucas)

Sua vez: Defina filho(Y, X) (Y é filho de X) e filha(Y, X) (Y é filha de X).

?- filho(pedro, carlos).true
?- filha(clara, ana).true
?- filho(X, carlos). → deve listar X = pedro, lucas.

Solução:

Raciocínio: Para ser filho(a), a pessoa deve ser descendente (pai ou mãe) e ter o gênero correspondente.

b) tio/2 e tia/2

Grafo para tio/2: T é tio de S se: 1. T é irmão de um dos pais de S 2. T é homem Caminho: T → (irmao) → Pai/Mãe de S T é homem

Sua vez: Defina tio(T, S) e tia(T, S).

?- tio(roberto, pedro).true (Roberto é irmão de Carlos)
?- tia(beatriz, lucas).true (Beatriz é irmã de Carlos)
?- tio(X, clara). → deve listar X = roberto.

Dica: Você precisará primeiro definir irmao/2 (já vimos) e irma/2 (versão feminina).

Solução:

Raciocínio: T é tio(a) se é irmão(ã) de um dos pais de S. Usamos as regras irmao/2 e irma/2 como auxiliares.

c) primo/2 e prima/2

Grafo para primo/2: P1 é primo de P2 se: 1. P1 e P2 têm um tio em comum 2. Não são irmãos 3. P1 é homem (para primo) Caminho: P1 → (pai/mãe) → Tio(a) comum → (pai/mãe) → P2

Sua vez: Defina primo(P1, P2) e prima(P1, P2).

?- primo(joao_jr, pedro).true (João Jr. e Pedro são primos)
?- prima(sofia, clara).true (Sofia e Clara são primas)
?- primo(X, lucas). → deve listar X = joao_jr.

Dica: Use a regra tio/2 ou tia/2 que você acabou de definir.

Solução:

Raciocínio: Para ser primo(a), a pessoa deve ter um tio(a) em comum com a outra, e não ser a mesma pessoa. Incluímos as quatro combinações possíveis (tio/pai, tia/mae, etc.) para garantir que a relação funcione em ambos os sentidos.

d) avo/2 (avô/avó)

Grafo para avo/2: A é avô/avó de N se: 1. A é pai/mãe de um dos pais de N 2. A é homem (para avô) ou mulher (para avó) Caminho: A → (pai/mãe) → P → (pai/mãe) → N

Sua vez: Defina avo(A, N) (avô) e avo(A, N) (avó).

?- avo(joao, pedro).true (João é avô de Pedro)
?- avo(maria, lucas).true (Maria é avó de Lucas)
?- avo(X, clara). → deve listar X = joao, maria.

Solução:

Raciocínio: O avô/avó é pai/mãe de um dos pais da criança. Usamos o gênero para diferenciar avô de avó.

📊 6. Visualizando as Relações com UML

Abaixo está a representação UML das principais relações que definimos, usando o formato PlantUML:

Diagrama UML mostrando as relações pai/mãe e algumas relações derivadas (irmão, primo).

7. Por que praticar com regras?

  • Pensamento lógico: Cada regra é uma pequena prova lógica que você constrói.
  • Reuso: Regras como irmao/2 e tio/2 podem ser combinadas para construir outras mais complexas.
  • Validação constante: Testar cada regra com consultas ajuda a garantir que a lógica está correta antes de avançar.
  • Base para IA: Sistemas especialistas e bases de conhecimento são construídos exatamente assim.

Dica final: Sempre comece com um grafo ou diagrama antes de codificar. Isso ajuda a visualizar as conexões e evita erros de lógica. Depois, codifique e teste exaustivamente.

Conclusão

Neste exercício, construímos uma árvore genealógica completa e definimos 8 relações derivadas usando apenas fatos básicos e regras. A prática de desenhar o grafo antes de codificar e validar com consultas é fundamental para dominar o Prolog.

Próximos passos: Tente adicionar mais pessoas na árvore, ou definir relações como bisavo/2, sobrinho/2 ou cunhado/2. Quanto mais você praticar, mais natural se torna o raciocínio lógico!


“A lógica é a anatomia do pensamento.” — John Locke

O Poder dos Grafos de Relacionamento

filósofo

Visualize regras antes de codificá-las — uma abordagem gráfica para projetar predicados lógicos.

1. Projetar regras com grafos

Antes de escrever uma única linha de Prolog, desenhe um grafo de relacionamento. Nele:

  • Objetos (pessoas, coisas) são nós.
  • Relacionamentos (pai, mãe, irmão) são arcos direcionados ou não.

Essa técnica força você a pensar na topologia da lógica: quem se conecta a quem, e quais caminhos definem a relação que você quer codificar.

2. Arcos pontilhados: a regra em construção

Use arcos sólidos para fatos conhecidos (ex.: pai(adão, caim)) e arcos pontilhados para a relação que está sendo definida (ex.: irmao/2). O arco pontilhado representa a inferência que a regra criará.

3. Exemplo clássico: irmao(X,Y)

Definição em Prolog:

Leitura: X é irmão de Y se existe um Z tal que Z é pai de X e Z é pai de Y, e X é diferente de Y.

Grafo da regra irmao/2

PlantUML Syntax:
@startuml
object Adao
object Caim
object Abel

Adao –> Caim : pai
Adao –> Abel : pai
Caim ..> Abel : irmao (inferido)

@enduml

Tradução lógica: O nó Adão é pai de Caim e de Abel. O arco pontilhado entre Caim e Abel representa a regra: “eles são irmãos porque compartilham o mesmo pai”. O grafo deixa explícito que a relação irmao não é um fato atômico, mas uma conexão derivada.

O código UML acima representa a mesma estrutura: arcos sólidos de paternidade e o arco pontilhado (relação derivada) de irmão.

5. A condição X \= Y — por que é essencial?

Com a condição X \= Y (diferente), garantimos que os dois argumentos sejam distintos.

Ou seja:Neste caso queremos garantir que o programa não chegue a conclusão errada que Caim é irmão dele mesmo, por isso a condição.

6. Consulta: irmao(caim, abel).

Com os fatos pai(adão, caim). e pai(adão, abel)., a consulta retorna:

E a consulta irmao(abel, caim). também é verdadeira, porque a regra é simétrica (embora não explicitamente, ela deriva de um pai comum).

7. Encontrando todos os pares de irmãos

Se tivermos mais filhos de Adão (ex.: pai(adão, set).), a consulta irmao(X, Y). enumerará todos os pares ordenados com X \= Y:

O Prolog gera todas as combinações de dois filhos do mesmo pai, excluindo a identidade.

8. Regras vs. Fatos — manutenibilidade

Definição por fatos (ruim):

Definição por regra (boa):

A regra é mantenível: ao adicionar um novo filho, todos os pares de irmãos são automaticamente inferidos. Com fatos, você precisaria adicionar O(n²) fatos manualmente — propenso a erros e esquecimentos.

9. Consistência com regras

Regras garantem consistência porque a lógica é centralizada. Se a definição de “irmão” mudar (ex.: incluir meios-irmãos), basta alterar uma única regra. Com fatos, você teria que revisar todas as combinações.

Além disso, a base de fatos (pai/mãe) permanece enxuta e semânticamente limpa — cada fato é uma verdade atômica, e as regras constroem o conhecimento derivado.

Recapitulando: grafos de relacionamento transformam a regra em uma imagem mental. Arcos pontilhados mostram o que será inferido, e a condição X \= Y é o guardião da lógica. Use essa técnica antes de iniciar seu código Prolog, pois ficará mais claro, correto e elegante.