Em Prolog, quando fazemos uma consulta que tem múltiplas respostas, o comportamento padrão é mostrar a primeira solução e aguardar o usuário pressionar ; (ponto-e-vírgula) para ver a próxima. Mas e se quisermos ver todas as respostas de uma vez, sem interação manual? É aí que entra o predicado fail/0.
O Problema: Respostas Sob Demanda
Considere a base de fatos:
d(0).
d(1).
A consulta ?- d(X). retorna:
X = 0 % aguarda ‘;’ para continuar
% usuário pressiona ‘;’
X = 1
% fim
Para ver as duas respostas, o usuário precisa interagir. Em muitas situações — como ao gerar relatórios, listar todos os registros de um banco de dados ou depurar — queremos que o programa imprima todas as soluções automaticamente.
A Solução: fail + Efeitos Colaterais
O predicado fail/0 é um predicado pré-definido que sempre falha. Quando usado em conjunto com efeitos colaterais (como write/1 e nl/0), ele força o backtracking repetidamente, gerando todas as soluções.
Programa 3.5: Gerando Todas as Combinações Binárias
bin :-
d(A), d(B), d(C),
write([A, B, C]), nl,
fail.Vamos executar:
[0, 0, 0]
[0, 0, 1]
[0, 1, 0]
[0, 1, 1]
[1, 0, 0]
[1, 0, 1]
[1, 1, 0]
[1, 1, 1]
false
Todas as 8 combinações foram impressas automaticamente, sem necessidade de pressionar
; nenhuma vez!
Passo a Passo da Execução
Entenda como o Prolog processa bin :- d(A), d(B), d(C), write, nl, fail.:
- Gera:
d(A)unifica com0(primeira solução). - Gera:
d(B)unifica com0. - Gera:
d(C)unifica com0. - Processa:
write([0,0,0])imprime a lista,nlpula linha. - Falha:
failforça o backtracking para o ponto de escolha mais recente —d(C). - Próxima:
d(C)unifica com1(segunda solução). - Repete: O ciclo continua: escreve
[0,0,1], falha, backtracking… - Esgotamento: Quando todas as combinações de
d(A), d(B), d(C)se esgotam,
ofailnão tem mais para onde voltar, e a regrabinfalha, retornando
false.
Este é o padrão de iteração em Prolog. A geração produz valores, o processamento (write, nl) os exibe, e o fail força a busca pela próxima combinação.
Comparação com Loops de Outras Linguagens
O padrão gerar → processar → fail é análogo a loops em linguagens imperativas:
Python
for a in [0,1]:
for b in [0,1]:
for c in [0,1]:
print([a,b,c])
Prolog
bin :-
d(A), d(B), d(C),
write([A,B,C]), nl,
fail.
Em Python, o loop é explícito com for. Em Prolog, o backtracking substitui o loop
— a iteração é conduzida pelo mecanismo de busca do Prolog, não por uma construção de controle explícita.
⚠️ Cuidados com fail
fail pode criar loops infinitos se não houver uma base que esgote as possibilidades.
Por exemplo, se você usar fail com um predicado que tem infinitas soluções (como between(0, inf, X)), o programa nunca terminará. Sempre certifique-se de que a parte “geradora” tem um número finito de soluções, ou inclua uma condição de parada.
fail com between/3 ou use o predicado forall/2 (que é uma abstração segura sobre esse padrão).
Exercícios Propostos
- Listar todos os números binários de 4 bits: Modifique o programa
bin
para gerar combinações de 4 dígitos ([A,B,C,D]). - Listar todos os filhos de um pai: Crie uma base de fatos
pai(pedro, joao).,
pai(pedro, maria)., etc., e usefailpara listar todos os filhos de Pedro. - Listar todas as capitais de estados: Com fatos
capital(estado, cidade),
usefailpara imprimir todas as capitais. - Contar soluções: Use
failcom um contador (inc/1)
para contar quantas soluções existem para uma consulta. - Desafio: Crie um predicado
listar_solucoes(Goal)que recebe uma meta
como argumento (usandocall/1) e imprime todas as soluções usandofail.
Conclusão
O fail é uma ferramenta elegante que transforma o backtracking em um mecanismo de iteração. Combinado com efeitos colaterais, ele permite gerar, processar e exibir todas as soluções de uma consulta automaticamente.
Essa é uma das características que tornam o Prolog único: o fluxo de controle é guiado pela busca lógica, e não por instruções passo-a-passo. Use fail com sabedoria, e ele se tornará um aliado poderoso para explorar todas as respostas que seus programas podem oferecer.