In primo luogo, ho letto tutti gli altri post su SO relativi all'uso dei tagli in Prolog e sicuramente vedremo i problemi relativi al loro utilizzo. Tuttavia, c'è ancora un po 'di chiarezza per me e mi piacerebbe risolvere questo una volta per tutte.Prolog: evitare punti di scelta ridondanti (non determinismo) con e senza operatore di taglio
Nell'esempio banale di seguito, ripetiamo ricorsivamente un elenco e controlliamo se ogni 2 ° elemento è uguale a uno. Nel fare ciò, il processo ricorsivo può finire in uno dei seguenti casi di base: rimane una lista vuota o una lista con un singolo elemento.
base([]).
base([_]).
base([_,H|T]) :- H =:= 1, base(T).
Quando eseguito:
?- time(base([1])).
% 0 inferences, 0.000 CPU in 0.000 seconds (74% CPU, 0 Lips)
true ;
% 2 inferences, 0.000 CPU in 0.000 seconds (83% CPU, 99502 Lips)
false.
?- time(base([3,1,3])).
% 2 inferences, 0.000 CPU in 0.000 seconds (79% CPU, 304044 Lips)
true ;
% 2 inferences, 0.000 CPU in 0.000 seconds (84% CPU, 122632 Lips)
false.
In tali situazioni, ho sempre usato un operatore taglio esplicito nel caso 2a base (cioè quella che rappresenta un elemento di sinistra della tabella) come di seguito per eliminare con il punto di scelta ridondante.
base([]).
base([_]) :- !.
base([_,H|T]) :- H =:= 1, base(T).
Ora otteniamo:
?- time(base([1])).
% 1 inferences, 0.000 CPU in 0.000 seconds (81% CPU, 49419 Lips)
true.
?- time(base([3,1,3])).
% 3 inferences, 0.000 CPU in 0.000 seconds (83% CPU, 388500 Lips)
true.
Capisco che il comportamento di questo taglio è specifico per la posizione della regola e può essere considerato come cattiva pratica.
Passando tuttavia, si potrebbe riposizionare i casi come segue:
base([_,H|T]) :- H =:= 1, base(T).
base([_]).
base([]).
che sarebbe anche eliminare il punto scelta ridondante senza utilizzare un taglio, ma naturalmente, avremmo semplicemente spostare il punto di scelta per domande con elenchi con una quantità pari di cifre come di seguito:
?- time(base([3,1])).
% 2 inferences, 0.000 CPU in 0.000 seconds (82% CPU, 99157 Lips)
true ;
% 2 inferences, 0.000 CPU in 0.000 seconds (85% CPU, 96632 Lips)
false.
Quindi, ovviamente, non è nemmeno una soluzione. Potremmo tuttavia adattare questo ordine di regole con un taglio come segue:
base([_,H|T]) :- H =:= 1, base(T), !.
base([_]).
base([]).
poiché in questo modo non sarebbero presenti punti di scelta. Alcune domande:
?- time(base([3])).
% 1 inferences, 0.000 CPU in 0.000 seconds (81% CPU, 157679 Lips)
true.
?- time(base([3,1])).
% 3 inferences, 0.000 CPU in 0.000 seconds (83% CPU, 138447 Lips)
true.
?- time(base([3,1,3])).
% 3 inferences, 0.000 CPU in 0.000 seconds (82% CPU, 393649 Lips)
true.
Tuttavia, ancora una volta, il comportamento di questo taglio funziona correttamente solo a causa dell'ordine delle regole. Se qualcuno riposizionare i casi di base torna alla forma originale come illustrato di seguito:
base([]).
base([_]).
base([_,H|T]) :- H =:= 1, base(T), !.
ci sarebbe ancora ottenere il comportamento indesiderato:
?- time(base([1])).
% 0 inferences, 0.000 CPU in 0.000 seconds (83% CPU, 0 Lips)
true ;
% 2 inferences, 0.000 CPU in 0.000 seconds (84% CPU, 119546 Lips)
false.
In questo genere di situazioni, ho sempre usato il singolo taglio nel secondo caso base, dato che sono l'unico ad aver letto il mio codice e mi sono abituato. Tuttavia, mi è stato detto in una delle mie risposte su un altro post SO che questo non è raccomandato dall'uso dell'operatore di taglio e che dovrei cercare di evitarlo il più possibile.
Questo mi porta alla mia domanda bipartita:
Se un taglio, indipendentemente dalla posizione della norma in cui è presente, non cambia comportamento, ma non la soluzione(come negli esempi sopra), è ancora considerato una cattiva pratica?
Se desidero eliminare un punto di scelta ridondante tipico come quello negli esempi sopra, al fine di rendere un predicato completamente deterministico, c'è qualche altro, consigliato, modo di realizzare questo piuttosto che usare i tagli?
Grazie in anticipo!
Significa veramente "H =: = 1'? Nota che questo obiettivo produce un errore se non viene istanziato 'H'. – false
Per essere onesto, non ho davvero pensato al test specifico negli esempi di codice, poiché mi riferivo piuttosto alla situazione di avere due casi base diversi. Ho aggiunto l'equivalente di un test solo per far accadere qualcosa durante la ricorsione, che potrebbe aiutarmi a chiarire la mia domanda. – SND