Search code examples
prologclpfdreification

Reification integration issues


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].

Alternative implementation

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.

The bottom line

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!


Solution

  • 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].