2012-12-22 9 views
11

Sto tentando di scrivere un predicato Prolog (CLP) che costruisca un vincolo che limiti la disuguaglianza di due elenchi.Limite di disuguaglianza di lista

Più formalmente, con due elenchi A=[A1,...,AN], B=[B1,...,BN] il vincolo è definito come (A1 #\= B1) #\/ (A2 #\= B2) #\/ ... #\/ (AN #\= BN).

Non sono sicuro di come creare questo vincolo dati due elenchi di lunghezza arbitraria. Questo è il mio tentativo Capisco perché non funziona, ma non è in grado di risolverlo.

any_different([], []). 
any_different([H1|T1], [H2|T2]):- 
    H1 #\= H2 #\/ any_different(T1, T2). 

risposta

9

Avrai voglia di costruire la disgiunzione e restituirlo attraverso un terzo argomento:

any_different([], [], V) :- 
    V #= 0. % no differences between [] and [] 
any_different([H1|T1], [H2|T2], Disj) :- 
    any_different(T1, T2, Disj0), 
    Disj #<==> (H1 #\= H2) #\/ Disj0. 

Ora, chiamando any_different(List1, List2, AnyDiff) contrains una variabile AnyDiff che è possibile passare al predicato di etichettatura con il vostro altre variabili. Dichiarando AnyDiff #= 0 è possibile limitare List1 e List2 uguali, mentre AnyDiff #= 1 causerà la loro disuguaglianza.

+1

Grazie. Questo è l'idioma che stavo cercando. – mscavnicky

4

Penso che, almeno in SWI-Prolog, il predicato dif/2 e biblioteca (clpfd) potrebbe essere un'alternativa alla reificazione:

?- L=[X,Y,Z], L ins 1..3, dif(L,[1,2,3]), label(L). 
L = [1, 1, 1], 
X = Y, Y = Z, Z = 1 ; 
L = [1, 1, 2], 
X = Y, Y = 1, 
Z = 2 ; 
... 
4

Ecco un'implementazione basata su sum/3 e clpfd reificazione (#<==>)/2 :

not_equals_reified(X, Y, B) :- 
    X #\= Y #<==> B. 

any_different(Xs, Ys) :- 
    maplist(not_equals_reified, Xs, Ys, Bs), 
    sum(Bs, #>, 0). 

utilizzando maplist/4 non abbiamo nemmeno bisogno di scrivere codice ricorsivo!