Paradigmas de Linguagens de Programação em Python: Python Lógico (Part. 09)
- #Python
O paradigma lógico baseia-se em declarar fatos e regras, deixando que o computador deduza respostas por meio de raciocínio lógico. Embora Python não seja uma linguagem lógica pura, é possível programar conceitos desse paradigma usando bibliotecas específicas, trazendo o poder da lógica declarativa para projetos reais.
Para ilustrar esse processo, vamos imaginar que somos Nico Robin, a arqueóloga de One Piece, tentando decifrar os antigos Poneglyphs. Assim como um desenvolvedor precisa entender, executar e corrigir seu código, Robin precisa interpretar símbolos, prever falhas e reagir a imprevistos durante a tradução de textos milenares.
🧩 Paradigma Lógico com Python
O paradigma lógico é fundamentado na ideia de que programas são conjuntos de sentenças lógicas, compostas por fatos e regras, e que a execução consiste em consultar essas sentenças para que o sistema deduza as respostas corretas automaticamente. Ele é amplamente utilizado em inteligência artificial, sistemas especialistas, e linguagens como Prolog, que têm suporte nativo para raciocínio lógico.
Embora Python não seja uma linguagem lógica pura, ele oferece ferramentas e bibliotecas que permitem programar com conceitos do paradigma lógico, combinando raciocínio declarativo com a flexibilidade do paradigma imperativo.
Uma das bibliotecas mais populares para programação lógica em Python é a kanren
(anteriormente conhecida como logpy
). Com ela, podemos definir relações, fatos e regras, e depois fazer consultas lógicas para obter respostas baseadas nesses dados.
Como funciona o kanren
?
- Relações: são estruturas que representam relações entre elementos (ex:
parent(X, Y)
significa "X é pai/mãe de Y"). - Fatos: instâncias de relações que definem o conhecimento base do sistema.
- Variáveis Lógicas: usadas para fazer consultas e encontrar valores que satisfazem as relações.
- Consultas: perguntas feitas para descobrir quais valores das variáveis tornam as relações verdadeiras.
Exemplo prático
python
from kanren import run, var, Relation, facts
# Criar a relação "detentor" (quem detém o Poneglyph)
detentor = Relation()
# Definir fatos da relação detentor
facts(detentor,
("Robin", "Poneglyph do Reino de Alabasta"),
("Robin", "Poneglyph do Reino de Wano"),
("Jinbe", "Poneglyph do Reino de Fishman Island"))
# Criar variável lógica para consulta
x = var()
# Consultar quais Poneglyphs Robin detém
poneglyphs_da_robin = run(0, x, detentor("Robin", x))
print(poneglyphs_da_robin)
# Saída esperada: ('Poneglyph do Reino de Alabasta', 'Poneglyph do Reino de Wano')
No exemplo acima, facts
adiciona dados à relação parent
, e run
executa a consulta para descobrir todos os valores de x
que satisfazem a relação parent(x, "Bart")
.
Por que usar lógica em Python?
- Expressividade: permite modelar problemas complexos com regras declarativas, que são mais fáceis de manter e entender.
- Dedução automática: o sistema encontra soluções para consultas complexas sem que o programador tenha que escrever todo o passo a passo.
- Integração com código Python: é possível misturar o paradigma lógico com código imperativo e orientado a objetos para criar soluções híbridas poderosas.
📚 Conceitos Básicos: Fatos, Regras e Consultas
- Fatos: declarações simples que representam dados.
- Regras: expressões que definem relações entre fatos.
- Consultas: perguntas feitas ao sistema para deduzir informações baseadas nos fatos e regras.
💻 Exemplo Prático com kanren
python
from kanren import run, var, Relation, facts
# Relação: quem encontrou qual Poneglyph
encontrou = Relation()
facts(encontrou,
("Robin", "Poneglyph de Skypiea"),
("Robin", "Poneglyph de Ohara"),
("Kozuki Oden", "Poneglyph de Laugh Tale"))
x = var()
# Quem encontrou o Poneglyph de Skypiea?
print(run(1, x, encontrou(x, "Poneglyph de Skypiea")))
Este código define uma relação de descoberta de Poneglyphs e consulta quem encontrou o de Skypiea.
🧮 Manipulação Lógica com sympy.logic
python
from sympy.logic.boolalg import Or, And, Not
from sympy import symbols
mapa_antigo, texto_decifrado = symbols('mapa_antigo texto_decifrado')
# A Robin só pode avançar se tiver um mapa ou conseguir decifrar o texto
proxima_etapa = And(Not(mapa_antigo), Or(texto_decifrado, mapa_antigo))
print(proxima_etapa.simplify())
Aqui representamos uma lógica: se o mapa não estiver disponível, Robin só poderá prosseguir se conseguir decifrar o texto. Usamos lógica simbólica para simplificar as condições.
🔄 Simulando Lógica Declarativa em Python Puro
Embora não tenha suporte nativo, é possível criar sistemas simples de lógica usando funções, listas e dicionários para representar fatos e regras e filtrar soluções.
python
# Fatos: personagens e ilhas visitadas
fatos = [
{"personagem": "Robin", "ilha": "Ohara"},
{"personagem": "Robin", "ilha": "Skypiea"},
{"personagem": "Luffy", "ilha": "Skypiea"},
{"personagem": "Zoro", "ilha": "Wano"},
]
# Regra: quem passou por Skypiea?
def passou_por(ilha):
return [f["personagem"] for f in fatos if f["ilha"] == ilha]
print(passou_por("Skypiea")) # ['Robin', 'Luffy']
Aqui criamos uma “regra” com uma função e usamos uma lista de dicionários como base de conhecimento. Essa é uma forma funcional e imperativa de simular inferência lógica.
🎯 Aplicações Práticas
A lógica declarativa é poderosa para sistemas que exigem raciocínio automático e decisões baseadas em regras. Veja alguns exemplos práticos:
🧠 Sistema especialista de decisão (Robin decifrando um Poneglyph)
python
def eh_importante(poneglyph):
return poneglyph.get("tipo") == "Road" or poneglyph.get("contém") == "História do Século Perdido"
p1 = {"ilha": "Wano", "tipo": "Road", "contém": "Rei dos Mares"}
p2 = {"ilha": "Ohara", "tipo": "Histórico", "contém": "História do Século Perdido"}
p3 = {"ilha": "Dressrosa", "tipo": "Histórico", "contém": "Eventos locais"}
print(eh_importante(p1)) # True
print(eh_importante(p2)) # True
print(eh_importante(p3)) # False
🗺️ Regras de navegação do bando com base nos registros de Robin
python
def deve_visitar(ilhas):
return [ilha for ilha in ilhas if ilha.get("poneglyph") and ilha["poneglyph"]["tipo"] == "Road"]
ilhas = [
{"nome": "Wano", "poneglyph": {"tipo": "Road"}},
{"nome": "Alabasta", "poneglyph": {"tipo": "Histórico"}},
{"nome": "Drum Island", "poneglyph": None},
]
print(deve_visitar(ilhas)) # [{'nome': 'Wano', 'poneglyph': {'tipo': 'Road'}}]
🧩 Consulta lógica para descobrir conexões entre símbolos nos Poneglyphs
python
pones = [
{"ilha": "Wano", "simbolos": {"d", "reino", "luz"}},
{"ilha": "Ohara", "simbolos": {"d", "livros"}},
{"ilha": "Skypiea", "simbolos": {"sinos", "luz"}},
]
def procurar_ilhas_com(simbolo):
return [p["ilha"] for p in pones if simbolo in p["simbolos"]]
print(procurar_ilhas_com("d")) # ['Wano', 'Ohara']
print(procurar_ilhas_com("luz")) # ['Wano', 'Skypiea']
🔍 Quebra-cabeça lógico: qual ilha tem mais símbolos únicos para Robin decifrar?
python
def ilha_mais_complexa(pones):
return max(pones, key=lambda p: len(p["simbolos"]))
pones = [
{"ilha": "Ohara", "simbolos": {"d", "livros", "tempo"}},
{"ilha": "Skypiea", "simbolos": {"luz", "sinos"}},
{"ilha": "Wano", "simbolos": {"reino", "d"}},
]
mais_complexa = ilha_mais_complexa(pones)
print(mais_complexa["ilha"]) # Ohara
⚠️ Desafios e Limitações
🚫 Backtracking manual: Robin precisa testar todas as traduções até achar a correta
python
pistas = ["lua", "reino", "voz", "d"]
def decifrar(pistas):
for tentativa in pistas:
print(f"Robin testando: {tentativa}")
if tentativa == "d":
print("🌟 Significado encontrado!")
break
decifrar(pistas)
🐢 Performance lenta com grandes registros: muitos Poneglyphs para processar
python
poneglyphs = [{"ilha": f"Ilha {i}", "conteudo": "???", "simbolos": ["a", "b", "c"]} for i in range(100000)]
# Filtrar ilhas que mencionam "d"
ilhas_d = [p for p in poneglyphs if "d" in p["simbolos"]]
print(len(ilhas_d)) # 0 – Nenhuma menciona "d"
🔗 Dependência de bibliotecas externas (como kanren): Robin sozinha não consegue tudo
python
try:
from kanren import run, var, Relation, facts
except ImportError:
print("🔗 Biblioteca kanren não encontrada. Robin não consegue usar lógica avançada sem ajuda externa.")
🔚 Conclusão
Integrar o paradigma lógico ao Python é como adicionar uma nova forma de pensar ao seu código — baseada em dedução, relações e inferência automática. Mesmo sem suporte nativo completo, bibliotecas como kanren
e sympy.logic
nos permitem simular esse estilo com elegância, aplicando lógica declarativa para modelar sistemas baseados em regras e conhecimento.
Mais do que escrever instruções, você passa a estruturar fatos e deixar que o programa tire conclusões por conta própria. Isso é especialmente poderoso em cenários onde as decisões precisam ser derivadas com base em múltiplas condições e relações.
Se a Nico Robin programasse, ela usaria o paradigma lógico como usa seus poderes: consultando informações espalhadas como se fossem Poneglyphs, cruzando dados para encontrar respostas escondidas e agindo com precisão a partir do conhecimento, não da força. Cada relação no código seria como um braço que busca a verdade entre os fatos — silencioso, certeiro e essencial
👉 No próximo artigo, vamos explorar sobre Python declarativo...