I posted the code below as an answer to this question and user "repeat" answered and commented that it's not logically pure and "if you are interested in a minimal change to your code that makes it preserve logical-purity, I suggest posting a new question about that. I'd be glad to answer it :)".
% minset_one(1 in D1, 1 in D2, D1, D2, D1Len, D2Len, T).
minset_one_(true, false, D1, _, _, _, D1).
minset_one_(false, true, _, D2, _, _, D2).
minset_one_(true, true, _, D2, D1Len, D2Len, D2) :- D1Len >= D2Len.
minset_one_(true, true, D1, _, D1Len, D2Len, D1) :- D1Len < D2Len.
minset_one(D1, D2, T) :-
(member(1, D1) -> D1check = true ; D1check = false),
(member(1, D2) -> D2check = true ; D2check = false),
length(D1, D1Len),
length(D2, D2Len),
minset_one_(D1check, D2check, D1, D2, D1Len, D2Len, T).
e.g.
?- D1 = [X,Y,Z], D2 = [U,V], minset_one(D1,D2,T).
D1 = [1, Y, Z],
D2 = T, T = [1, V],
U = X, X = 1 ;
false
there are more solutions possible. member(1, D1)
is not backtracking through [1, Y, Z]
, then [X, 1, Z]
then [X, Y, 1]
.
The Problem with
(->)/2
(and friends)Consider the following goal:
(->)/2
commits to the first answer ofmember(1,D1)
—other answers are disregarded.Can alternatives to
(->)/2
—like(*->)/2
(SWI, GNU) orif/3
(SICStus)—help us here?No. These do not ignore alternative answers to make
member(1,D1)
succeed, but they do not consider that the logical negation ofmember(1,D1)
could also have succeeded.Back to basics: "If P then Q else R" ≡ "(P ∧ Q) ∨ (¬P ∧ R)"
So let's rewrite
(If -> Then ; Else)
as(If, Then ; Not_If, Else)
:How should we implement
non_member(X,Xs)
—can we simply write\+ member(X,Xs)
?No! To preserve logical purity we better not build upon "negation as finite failure".
Luckily, combining
maplist/2
anddif/2
does the job here:Putting it all together
So here's the minimum change I propose:
Running the sample query we now get:
Better. Sure looks to me like there's nothing missing.