Quali sono gli usi del predicato fallito in Prolog?

Non riesco a trovare una situazione in cui ne avrei bisogno.

I sistemi eleganti forniscono false/0 come sinonimo dichiarativo per l’imperativo fail/0 . Un esempio in cui è utile è quando vuoi forzare manualmente il backtracking per effetti collaterali, come:

 ?- between(1,3,N), format("line ~w\n", [N]), false. line 1 line 2 line 3 

Invece di false/0 , puoi anche utilizzare qualsiasi objective che non riesce, ad esempio un po ‘più breve:

 ?- between(1,3,N), format("line ~w\n", [N]), 0=1. line 1 line 2 line 3 

Quindi, false/0 non è strettamente necessario, ma piuttosto bello.

EDIT : A volte vedo i principianti che vogliono dichiarare per esempio “la mia relazione non è valida per la lista vuota”, e poi aggiungere:

my_relation([]) :- false.

al loro codice. Questo non è necessario e non è un buon esempio di utilizzo di false/0 , ad eccezione, ad esempio, delle slice di errore generate a livello di codice. Invece, concentrati sull’affermazione delle cose che riguardano la tua relazione. In questo caso, basta tralasciare l’intera clausola e definire la relazione solo per gli elenchi che non sono vuoti, cioè che hanno almeno un elemento:

my_relation([L|Ls]) :- etc.

oppure, se stai descrivendo altri termini oltre agli elenchi, utilizza un vincolo come:

my_relation(T) :- dif(T, []), etc.

Dato solo uno (o anche entrambi) di queste due clausole, la query ?- my_relation([]). fallirà automaticamente. Non è necessario introdurre una clausola aggiuntiva che non abbia mai successo a tale scopo.

Fallimento esplicito. fail viene spesso utilizzato insieme a cut: ... !, fail. per far rispettare il fallimento.

Per tutti i costrutti. L’uso esplicito di fail / false per enumerare tramite backtracking è un’attività molto soggetta a errori. Considera un caso:

 ... ( generator(X), action(X), fail ; true ), ... 

L’idea è quindi di “fare” l’azione per tutto X Ma cosa succede se l’ action(X) fallisce? Questo costrutto continua semplicemente con il prossimo candidato – come se nulla fosse accaduto. In questo modo alcuni errori possono rimanere inosservati per molto tempo.

Per questi casi è meglio usare \+ ( generator(X), \+ action(X) ) che fallisce, se l’ action(X) fallisce per qualche X Alcuni sistemi offrono questo come forall/2 integrato. Personalmente, preferisco usare \+ in questo caso perché \+ è un po ‘più chiaro che il costrutto non lascia un legame.

Failure-slice. Per scopi diagnostici è spesso utile aggiungere di proposito false nei tuoi programmi. Vedi slice-failure per maggiori dettagli.

Un caso (tratto da Constraint Logic Programming usando Eclipse ) è un’implementazione di not / 1:

 :- op(900, fy, not). not Q :- Q, !, fail. not _ . 

Se Q riesce, il taglio (!) Fa scartare la seconda clausola, e il fallimento assicura un risultato negativo. Se Q fallisce, allora la seconda non clausola scocca per prima.

Un altro uso per fallire è forzare il backtracking attraverso alternative quando si usano predicati con effetti collaterali:

 writeall(X) :- member(A,X), write(A), fail. writeall(_). 

Alcune persone potrebbero non considerare questo stile di programmazione particolarmente buono. 🙂