2010-06-08 12 views

risposta

16

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.

+0

s/elegante/elegante e conforme/ – false

2

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.

1

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ò. :)

+0

Oops, sembra che mi abbia colpito. – hdan

7

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 per maggiori dettagli.