Reification of term equality/inequality

前端 未结 6 1638
天涯浪人
天涯浪人 2020-11-22 16:45

Pure Prolog programs that distinguish between the equality and inequality of terms in a clean manner suffer from execution inefficiencies ; even when all terms of relevance

6条回答
  •  有刺的猬
    2020-11-22 17:10

    The following code is based on if_/3 and (=)/3 (a.k.a. equal_truth/3), as implemented by @false in Prolog union for A U B U C:

    =(X, Y, R) :- X == Y,    !, R = true.
    =(X, Y, R) :- ?=(X, Y),  !, R = false. % syntactically different
    =(X, Y, R) :- X \= Y,    !, R = false. % semantically different
    =(X, Y, R) :- R == true, !, X = Y.
    =(X, X, true).
    =(X, Y, false) :-
       dif(X, Y).
    
    if_(C_1, Then_0, Else_0) :-
       call(C_1, Truth),
       functor(Truth,_,0),  % safety check
       ( Truth == true -> Then_0 ; Truth == false, Else_0 ).
    

    Compared to occurrences/3, the auxiliary occurrences_aux/3 uses a different argument order that passes the list Es as the first argument, which can enable first-argument indexing:

    occurrences_aux([], _, []).
    occurrences_aux([X|Xs], E, Ys0) :-
       if_(E = X, Ys0 = [X|Ys], Ys0 = Ys),
       occurrences_aux(Xs, E, Ys).
    

    As pointed out by @migfilg, the goal Fs=[1,2], occurrences_aux(Es,E,Fs) should fail, as it is logically false: occurrences_aux(_,E,Fs) states that all elements in Fs are equal to E. However, on its own, occurrences_aux/3 does not terminate in cases like this.

    We can use an auxiliary predicate allEqual_to__lazy/2 to improve termination behaviour:

    allEqual_to__lazy(Xs,E) :-
       freeze(Xs, allEqual_to__lazy_aux(Xs,E)).
    
    allEqual_to__lazy_aux([],_).
    allEqual_to__lazy_aux([E|Es],E) :-
       allEqual_to__lazy(Es,E).
    

    With all auxiliary predicates in place, let's define occurrences/3:

    occurrences(E,Es,Fs) :-
       allEqual_to__lazy(Fs,E),    % enforce redundant equality constraint lazily
       occurrences_aux(Es,E,Fs).   % flip args to enable first argument indexing
    

    Let's have some queries:

    ?- occurrences(E,Es,Fs).       % first, the most general query
    Es = Fs, Fs = []        ;
    Es = Fs, Fs = [E]       ;
    Es = Fs, Fs = [E,E]     ;
    Es = Fs, Fs = [E,E,E]   ;
    Es = Fs, Fs = [E,E,E,E] ...    % will never terminate universally, but ...
                                   % that's ok: solution set size is infinite
    
    ?- Fs = [1,2], occurrences(E,Es,Fs).
    false.                         % terminates thanks to allEqual_to__lazy/2
    
    ?- occurrences(E,[1,2,3,1,2,3,1],Fs).
    Fs = [1,1,1],     E=1                     ;
    Fs = [2,2],                 E=2           ;
    Fs = [3,3],                           E=3 ;
    Fs = [],      dif(E,1), dif(E,2), dif(E,3).
    
    ?- occurrences(1,[1,2,3,1,2,3,1],Fs).
    Fs = [1,1,1].                  % succeeds deterministically
    
    ?- Es = [E1,E2], occurrences(E,Es,Fs).
    Es = [E,  E], Fs = [E,E],     E1=E ,     E2=E  ;
    Es = [E, E2], Fs = [E],       E1=E , dif(E2,E) ;
    Es = [E1, E], Fs = [E],   dif(E1,E),     E2=E  ;
    Es = [E1,E2], Fs = [],    dif(E1,E), dif(E2,E).
    
    ?- occurrences(1,[E1,1,2,1,E2],Fs).
        E1=1 ,     E2=1 , Fs = [1,1,1,1] ;
        E1=1 , dif(E2,1), Fs = [1,1,1]   ;
    dif(E1,1),     E2=1 , Fs = [1,1,1]   ;
    dif(E1,1), dif(E2,1), Fs = [1,1].
    

    Edit 2015-04-27

    Some more queries for testing if the occurrences/3 universal terminates in certain cases:

    ?-           occurrences(1,L,[1,2]).
    false. 
    ?- L = [_|_],occurrences(1,L,[1,2]).
    false.
    ?- L = [X|X],occurrences(1,L,[1,2]).
    false.
    ?- L = [L|L],occurrences(1,L,[1,2]).
    false.
    

提交回复
热议问题