2012-12-22 12 views
11

Próbuję napisać predykat Prolog (CLP), który zbuduje ograniczenie ograniczające nierówność dwóch list.Lista ograniczenia nierówności

Bardziej formalnie, mając dwie listy A=[A1,...,AN], B=[B1,...,BN] ograniczenie definiowane jest jako (A1 #\= B1) #\/ (A2 #\= B2) #\/ ... #\/ (AN #\= BN).

Nie jestem pewien, jak zbudować to ograniczenie, biorąc pod uwagę dwie listy o dowolnej długości. To jest moja próba. Rozumiem, dlaczego to nie działa, ale nie można go naprawić.

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

Odpowiedz

9

Będziemy chcieli budować alternatywę i odesłać go za pośrednictwem trzeciego argumentu:

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. 

Teraz, nazywając any_different(List1, List2, AnyDiff) contrains zmienna AnyDiff które można przekazać do orzecznika oznakowania wraz z inne zmienne. Podając AnyDiff #= 0 można ograniczyć List1 i List2 jako równe, a AnyDiff #= 1 spowoduje, że będą nierówne.

+1

Dziękuję. To jest idiom, którego szukałem. – mscavnicky

4

myślę, że przynajmniej w SWI-Prolog, The (clpfd) orzeczenie DIF/2 i biblioteka może być alternatywą dla reifikację:

?- 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

Oto implementacja na podstawie sum/3 i clpfd reifikację (#<==>)/2 :

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

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

korzystając maplist/4 nawet nie trzeba pisać kodu rekurencyjnego!