Em Prolog, a base de dados é geralmente estática: os fatos e regras são definidos
no arquivo e não mudam durante a execução. No entanto, muitas aplicações precisam de
flexibilidade — adicionar novos dados, remover informações obsoletas ou
modificar regras em tempo de execução. Para isso, o Prolog oferece uma base de dados dinâmica.
1. O Conceito de Base de Dados Dinâmica
Uma base de dados dinâmica permite que cláusulas (fatos e regras) sejam
adicionadas ou removidas durante a execução do programa.
Isso é útil para:
- Sistemas interativos (ex: cadastro de usuários).
- Bases de conhecimento que evoluem.
- Algoritmos que constroem soluções incrementalmente.
- Memorização de resultados (memoização).
2. A Diretiva :‑ dynamic
Para tornar um predicado dinâmico, usamos a diretiva :- dynamic seguida do nome e aridade do predicado.
|
|
% Declara que o predicado joga/2 é dinâmico :- dynamic joga/2. % Agora podemos adicionar e remover fatos joga/2 em tempo de execução |
Sem essa declaração, tentar modificar um predicado resultaria em erro.
3. Predicados de Manipulação
O Prolog fornece três predicados principais para manipular a base de dados dinâmica:
| Predicado |
Descrição |
asserta/1 |
Adiciona uma cláusula no início da base de dados (antes das existentes). |
assertz/1 |
Adiciona uma cláusula no final da base de dados (depois das existentes). |
retract/1 |
Remove a primeira cláusula que unifica com o argumento. |
retractall/1 |
Remove todas as cláusulas que unificam com o argumento. |
Além disso, listing/0 ou listing(predicado) exibe a base de dados atual.
4. Programa 6.1: Jogadores
Vamos começar com uma base de dados simples de jogadores e seus esportes:
|
|
% Declara que joga/2 é dinâmico :- dynamic joga/2. % Fatos iniciais joga(pelé, futebol). joga(guga, tênis). |
Para ver a base atual, use listing(joga) ou listing/0.
|
|
?- listing(joga). :- dynamic joga/2. joga(pelé, futebol). joga(guga, tênis). true. |
5. Adicionando Novos Fatos com assertz/1
assertz/1 adiciona um fato no final da base.
|
|
?- assertz(joga(maradona, futebol)). true. ?- listing(joga). :- dynamic joga/2. joga(pelé, futebol). joga(guga, tênis). joga(maradona, futebol). % Adicionado no final true. |
Como resultado, a consulta joga(X, futebol) retorna os jogadores na ordem em que foram inseridos.
|
|
?- joga(X, futebol). X = pelé ; X = maradona. |
6. Adicionando com asserta/1
asserta/1 adiciona um fato no início da base.
|
|
?- asserta(joga(robinho, futebol)). true. ?- listing(joga). :- dynamic joga/2. joga(robinho, futebol). % Adicionado no início joga(pelé, futebol). joga(guga, tênis). joga(maradona, futebol). true. |
Agora, joga(X, futebol) retorna robinho primeiro:
|
|
?- joga(X, futebol). X = robinho ; X = pelé ; X = maradona. |
7. Removendo Fatos com retract/1
retract/1 remove a primeira cláusula que unifica com o argumento.
|
|
?- retract(joga(guga, tênis)). true. ?- listing(joga). :- dynamic joga/2. joga(robinho, futebol). joga(pelé, futebol). joga(maradona, futebol). true. |
Também podemos remover usando variáveis:
|
|
?- retract(joga(maradona, _)). true. ?- listing(joga). :- dynamic joga/2. joga(robinho, futebol). joga(pelé, futebol). true. |
Importante: O retract/1 remove apenas a primeira cláusula
que unifica. Para remover todas, use retractall/1.
|
|
?- retractall(joga(_, futebol)). true. ?- listing(joga). :- dynamic joga/2. true. % Nenhum fato restante |
8. Exemplo Prático: Sistema de Agenda
Vamos construir um pequeno sistema de agenda telefônica usando base dinâmica:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
:- dynamic telefone/2. % Adicionar um contato add_contato(Nome, Numero) :- assertz(telefone(Nome, Numero)). % Remover um contato remove_contato(Nome) :- retractall(telefone(Nome, _)). % Buscar um número buscar_numero(Nome, Numero) :- telefone(Nome, Numero). % Listar todos os contatos listar_contatos :- telefone(Nome, Numero), write(Nome), write(' - '), write(Numero), nl, fail. listar_contatos. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
?- add_contato(joao, '1234-5678'). true. ?- add_contato(maria, '8765-4321'). true. ?- listar_contatos. joao - 1234-5678 maria - 8765-4321 true. ?- buscar_numero(joao, N). N = '1234-5678'. ?- remove_contato(joao). true. ?- listar_contatos. maria - 8765-4321 true. |
9. Cuidados e Boas Práticas
O uso de base de dados dinâmica é poderoso, mas requer atenção:
-
Ordene com cuidado: A ordem dos fatos afeta a ordem das soluções e o backtracking.
-
Evite efeitos colaterais inesperados: Modificar a base durante uma consulta pode
causar comportamentos imprevisíveis.
-
Use
retract com unificação específica: Se usar variáveis, certifique-se
de que elas estão instanciadas para evitar remoções indesejadas.
-
Organize o código: Declare todos os predicados dinâmicos no início do arquivo
com
:- dynamic.
10. Exercícios Propostos
-
Sistema de Estoque: Crie um predicado dinâmico
estoque(Produto, Quantidade)
com funções para adicionar, remover e consultar produtos. Inclua verificação de quantidade negativa.
-
Histórico de Operações: Implemente um sistema que registra todas as operações
(adições e remoções) em um predicado
log/2 com timestamp.
-
Memoização: Implemente
fib_memo(N, F) que calcula Fibonacci
armazenando resultados já calculados para reutilização.
-
Base de Alunos: Crie um sistema de cadastro de alunos com
aluno(Nome, Nota)
e funções para adicionar, remover, e calcular a média da turma.
11. Conclusão
A base de dados dinâmica é um recurso poderoso que estende a capacidade do Prolog
para aplicações interativas e em evolução. Com asserta/1, assertz/1
e retract/1, podemos:
- Construir sistemas que aprendem com novos dados.
- Implementar caches e memoização para otimização.
- Criar interfaces interativas com o usuário.
- Manter bases de conhecimento atualizadas.
Use com responsabilidade: base dinâmica é uma ferramenta poderosa, mas seu uso indevido
pode tornar o programa difícil de depurar. Sempre documente os predicados dinâmicos e
planeje a estratégia de modificação da base.