Aritmética e Comparações em Prolog

filósofo
Lidando com números de forma declarativa — e sem sustos

Se você vem de linguagens como Python, Java ou C, pode estranhar o comportamento do Prolog com números.
Prolog não avalia expressões aritméticas automaticamente.
Ao contrário do que acontece em 2 + 3 em Python (que já retorna 5),
em Prolog a expressão 2 + 3 é apenas uma estrutura simbólica — a não ser
que você peça explicitamente para avaliá-la.

Neste artigo, vamos explorar como fazer cálculos, comparar valores numéricos e extrair informações
de uma base de dados de países. Tudo com exemplos práticos e explicações passo a passo.

1. Prolog não avalia automaticamente

Em Prolog, termos como 2 + 3 são vistos como uma estrutura com um operador functor +
e dois argumentos. Se você perguntar X = 2 + 3, o Prolog unificará X com a
estrutura +(2,3), e não com o número 5. Para efetivamente calcular, precisamos
de um predicado especial: is/2.

🧠 Lembre-se: is/2 é um predicado que avalia a expressão
aritmética do lado direito e unifica o resultado com o lado esquerdo (que deve ser uma variável ou um número).

2. O predicado is/2 — o avaliador

O uso clássico é: X is 2 + 3. Isso faz o Prolog calcular 2 + 3 e unificar
X com 5.

?- X is 2 + 3.
X = 5.

is/2 só funciona se o lado direito for uma expressão aritmética totalmente instanciada
(sem variáveis). Caso contrário, ocorrerá um erro.

3. Operadores aritméticos no Prolog

O Prolog oferece os operadores que você espera, com algumas particularidades:

  • + adição
  • - subtração
  • * multiplicação
  • / divisão real (resultado em ponto flutuante)
  • // divisão inteira (trunca para inteiro)
  • mod resto da divisão inteira
  • ^ exponenciação (potência)

 

4. Base de dados: países (área, população)

Vamos trabalhar com uma base de fatos no estilo país(nome, área, população),
onde área está em milhões de km² e população em milhões de habitantes.


 

5. Calculando densidade demográfica

A densidade populacional é D = P / A (população / área). Vamos criar uma regra
que calcula a densidade de um país.


 

Consultando:


 

🔎 Interpretação: O Brasil tem cerca de 25 habitantes por milhão de km² (na verdade,
usando milhões, a unidade fica coerente).

6. Predicados de comparação

Para comparar valores numéricos, usamos os seguintes operadores (todos avaliados aritmeticamente):

  • =:= igualdade aritmética (ex: 2 + 3 =:= 5 é verdadeiro)
  • =\= diferente aritmético
  • > maior que
  • < menor que
  • >= maior ou igual
  • =< menor ou igual (atenção: não é <= !)

 

7. “A área do Brasil é igual à área dos EUA?”

Para comparar áreas, podemos consultar diretamente:

?- país(brasil, A1, _), país(eua, A2, _), A1 =:= A2.
false.

O resultado é false, pois as áreas são diferentes (8.516 vs 9.834).

Se quiséssemos países com a mesma área (o que não ocorre nessa base), poderíamos usar
=:= na condição.

8. Selecionando dados: “Países com população > 500 milhões?”

Podemos usar comparações dentro de regras ou consultas para filtrar países.


 

Também podemos criar uma regra:


 

Consultando: ?- populoso(X). retorna X = india.

📊 Outras perguntas:
• Países com área maior que 5 milhões de km²? ?- país(N, A, _), A > 5. → Brasil, EUA.
• Densidade maior que 100? ?- país(N, A, P), D is P/A, D > 100. → Índia (≈426), Portugal (≈112).

9. Atenção: = (unificação) vs =:= (igualdade aritmética)

Essa é uma das maiores fontes de confusão para quem está aprendendo Prolog:

  • = é o operador de unificação. Ele tenta tornar dois termos
    sintaticamente idênticos, sem avaliar expressões aritméticas.
  • =:= é um predicado que avalia ambas as expressões
    aritméticas e compara os resultados numéricos.

 

⚠️ Importante: Use =:= e =\= para comparar valores numéricos.
Use = para unificar termos (inclusive variáveis). Para diferença sintática, use \=.


✅ A aritmética em Prolog é poderosa, mas exige precisão: use is/2 para calcular,
=:= para comparar valores e lembre-se que = é unificação, não igualdade numérica.
Pratique com a base de países e explore outras métricas como densidade, crescimento ou PIB per capita.

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