O operador de corte, representado por !, é uma das
ferramentas mais poderosas — e perigosas — do Prolog. Ele permite controlar o backtracking,
eliminando alternativas desnecessárias e otimizando a execução. Mas como toda ferramenta poderosa,
seu uso requer cuidado: um corte mal colocado pode eliminar soluções válidas e alterar
a semântica declarativa do programa.
O Problema: Backtracking Desnecessário
Considere a função matemática f(X) definida por partes, como no Programa 3.2:
% f(X) = 0 se X < 5
% f(X) = 1 se 5 =< X < 10
% f(X) = 2 se X >= 10
f(X, 0) :- X < 5.
f(X, 1) :- X >= 5, X < 10.
f(X, 2) :- X >= 10.
As regras são mutuamente exclusivas: para qualquer X, apenas uma delas
será verdadeira. No entanto, o Prolog não sabe disso. Ao consultar ?- f(3, Y)., ele:
- Tenta a primeira regra:
X < 5é verdadeiro, entãoY = 0. - Se pedirmos mais soluções (
;), ele retrocede e tenta a segunda regra,
testandoX >= 5(que falha). - Depois tenta a terceira regra, que também falha.
Esse backtracking inútil desperdiça tempo, especialmente em programas com muitas regras
ou bases de dados grandes. Precisamos de uma forma de dizer ao Prolog: “se esta regra funcionou,
não tente as outras”.
A Solução: O Operador de Corte (!)
O corte é um predicado especial que sempre é bem-sucedido, mas com
um efeito colateral: ele descarta todos os pontos de escolha criados
antes de sua posição dentro da mesma regra e descarta as cláusulas restantes para aquele
predicado. Veja o Programa 3.3 com cortes:
f(X, 0) :- X < 5, !.
f(X, 1) :- X >= 5, X < 10, !.
f(X, 2) :- X >= 10.
Agora, quando consultamos ?- f(3, Y).:
- A primeira regra é ativada,
X < 5é verdadeiro. - O corte
!é executado: ele descarta as alternativas paraf/2
(as regras 2 e 3) e também descarta qualquer backtracking dentro da regra (embora não haja). - O Prolog não tenta mais as outras regras, economizando tempo.
Árvore de Busca: Antes e Depois do Corte
Visualize a diferença na árvore de busca para ?- f(3, Y).:
├─ f(3, Y)
│ ├─ Regra 1: X < 5 ✅ → Y = 0 (solução)
│ │ └─ ↩️ backtracking
│ ├─ Regra 2: X >= 5 ❌ (falha)
│ └─ Regra 3: X >= 10 ❌ (falha)
│
COM CORTE
├─ f(3, Y)
│ ├─ Regra 1: X < 5 ✅ → ! (solução)
│ │ └─ ✂️ pontos de escolha descartados
│ └─ (Regras 2 e 3 não são tentadas)
Estrutura Condicional com Corte (Programa 3.4)
O corte é frequentemente usado para implementar estruturas condicionais do tipo
if-then-else:
if(Condition, Then, Else) :-
Condition, !,
Then.
if(_, _, Else) :-
Else.
A primeira cláusula tenta a condição. Se for bem-sucedida, o corte previne que a segunda
cláusula seja usada, e executa Then. Se a condição falhar, a primeira cláusula falha,
e o Prolog tenta a segunda (o Else).
?- if(X < 5, write('pequeno'), write('grande')).• Se
X for instanciado com um valor, ele escreve a mensagem correta.• O corte garante que apenas uma das mensagens seja escrita.
Os Perigos do Corte
se usado incorretamente.
Um exemplo clássico de erro:
% ERRADO — este corte elimina soluções legítimas
pai(X, Y) :- homem(X), !, filho(Y, X).
Aqui, o corte impede que o Prolog tente outras cláusulas de pai/2 mesmo que homem(X)
seja verdadeiro, eliminando potencialmente outros pais que poderiam ser encontrados em outras regras.
O corte é uma “fuga do paradigma declarativo puro”.
Em Prolog puro, a ordem das cláusulas não afeta o resultado (apenas a eficiência).
Com o corte, a ordem passa a importar semanticamente. Programas com cortes
são mais difíceis de ler, depurar e manter.
Boas Práticas com Corte
- Use o corte apenas quando as cláusulas são mutuamente exclusivas e você tem certeza
de que as alternativas não devem ser consideradas. - Coloque o corte após a condição que determina a exclusividade, não antes.
- Prefira estruturas condicionais com
->(o operador condicional do Prolog)
em vez de cortes manuais, quando possível. - Documente o uso do corte com comentários explicando por que ele está ali.
Exercícios Propostos
- Função sinal: Escreva a função
sinal(X, S)que retornaS = -1
seX < 0,S = 0seX = 0, eS = 1seX > 0.
Use cortes para otimizar. - Classificação de idade: Crie
idade_class(X, C)ondeCé
'crianca'seX < 12,'adolescente'se12 =< X < 18,
e'adulto'seX >= 18. Use cortes. - Teste sem cortes: Execute as mesmas funções sem cortes e compare
o comportamento quando você pede soluções alternativas com;. - Desafio: Implemente a estrutura
if/3apresentada acima e teste com
diferentes condições, incluindo casos em que a condição tem múltiplas soluções.
Conclusão
O operador de corte é uma ferramenta valiosa para otimização e controle
do backtracking, mas deve ser usado com moderação e consciência. Ele quebra a pureza
declarativa do Prolog, tornando o programa mais procedural. Em muitas situações, a ordenação
adequada das cláusulas e o uso de cortes verdes (que apenas otimizam, sem
alterar o resultado) são suficientes. Use o corte quando a eficiência realmente importar, mas sempre
com a certeza de que ele não eliminará soluções corretas.