Non riesco a trovare una situazione in cui ne avessi bisogno.Quali sono gli usi del predicato di errore in Prolog?
risposta
I sistemi eleganti forniscono false/0
come sinonimo dichiarativo dell'imperativo fail/0
. Un esempio in cui è utile è quando si desidera manualmente forzare backtracking per gli effetti collaterali, come:
?- between(1,3,N), format("line ~w\n", [N]), false.
line 1
line 2
line 3
Invece di false/0
, è anche possibile utilizzare qualsiasi obiettivo che non riesce, ad esempio un po 'più corta:
?- 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 affermare per esempio "il mio rapporto non vale per la lista vuota", e quindi 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 fette di errore generate a livello di codice. Invece, concentrati sull'affermazione delle cose che detengono sulla tua relazione. In questo caso, lasciare l'intera clausola, e definire la relazione solo per liste non vuote, cioè, avere almeno un elemento:
my_relation([L|Ls]) :- etc.
oppure, se si sta descrivendo altri termini in aggiunta a liste così, usare un vincolo simile:
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.
Un caso (tratta da Constraint Logic Programming using Eclipse) è un'implementazione di non/1: (!)
:- op(900, fy, not).
not Q :- Q, !, fail.
not _ .
Se Q riesce, il taglio provoca la seconda non clausola essere scartata, e il fail assicura un negativo risultato. Se Q fallisce, allora la seconda non clausola scocca per prima.
Un altro uso per fallire è per forza backtracking attraverso alternative quando si utilizzano predicati con effetti collaterali:
writeall(X) :- member(A,X), write(A), fail.
writeall(_).
Alcune persone potrebbero non considerare questo particolarmente buono stile di programmazione però. :)
Oops, sembra che mi abbia colpito. – hdan
Errore esplicito.fail
viene spesso utilizzato insieme al taglio: ... !, fail.
per imporre l'errore.
Per tutti i costrutti. L'uso esplicito di fail
/false
per elencare tramite il backtracking è un'attività molto soggetta a errori.Si consideri un caso:
... (generator(X), action(X), fail ; true), ...
L'idea è quindi quella di "fare" l'azione per tutti X
. Ma cosa succede se 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 tali casi è preferibile utilizzare \+ (generator(X), \+ action(X))
che non riesce, in caso di errore action(X)
per alcuni X
. Alcuni sistemi offrono questo come forall/2
integrato. Personalmente, preferisco usare \+
in questo caso perché lo \+
è un po 'più chiaro che il costrutto non lascia un legame.
Failure-slice. Per scopi diagnostici è spesso utile aggiungere lo false
allo scopo nei programmi. Vedi failure-slice per maggiori dettagli.
s/elegante/elegante e conforme/ – false