I offered the following clpfd-based code for the recent question Segregating Lists in Prolog:
list_evens_odds([],[],[]).
list_evens_odds([X|Xs],[X|Es],Os) :-
X mod 2 #= 0,
list_evens_odds(Xs,Es,Os).
list_evens_odds([X|Xs],Es,[X|Os]) :-
X mod 2 #= 1,
list_evens_odds(Xs,Es,Os).
It is concise and pure, but can leave behind many unnecessary choice-points. Consider:
?- list_evens_odds([1,2,3,4,5,6,7],Es,Os).
Above query leaves behind a useless choice-point for every non-odd item in [1,2,3,4,5,6,7]
.
Using the reification technique demonstrated by @false in Prolog union for A U B U C can reduce the number of unnecessary choice-points. The implementation could change to:
list_evens_odds([],[],[]).
list_evens_odds([X|Xs],Es,Os) :-
if_(#<=>(X mod 2 #= 0), (Es=[X|Es0],Os= Os0),
(Es= Es0, Os=[X|Os0])),
list_evens_odds(Xs,Es0,Os0).
To directly interact with clpfd-reification the implementation of if_/3
could be adapted like this:
if_( C_1, Then_0, Else_0) :-
call(C_1,Truth01),
indomain(Truth01),
( Truth01 == 1 -> Then_0 ; Truth01 == 0, Else_0 ).
Of course, (=)/3
would also need to be adapted to this convention.
So I wonder: Is using 0
and 1
as truth-values instead of false
and true
a good idea?
Am I missing problems along that road? Help, please! Thank you in advance!
In SWI-Prolog, you can use zcompare/3
:
:- use_module(library(clpfd)).
list_evens_odds([], [], []).
list_evens_odds([X|Xs], Es, Os) :-
Mod #= X mod 2,
zcompare(Ord, 0, Mod),
ord_(Ord, X, Es0, Es, Os0, Os),
list_evens_odds(Xs, Es0, Os0).
ord_(=, X, Es0, [X|Es0], Os, Os).
ord_(<, X, Es, Es, Os0, [X|Os0]).
Example query:
?- list_evens_odds([1,2,3,4,5,6,7], Es, Os).
Es = [2, 4, 6],
Os = [1, 3, 5, 7].