prolog

How can I "associate" vars to terms in Prolog


In Prolog, when I enter at the toplevel something like this:

X = [a-A, b-B, a-A].

I've associated some logical variables to terms using the - functor-- but importantly, the first and last pair in the list both have the same logical variable.

Let's say I have a list like this:

[a, b, a]

Is there any way to go from that to a list like the above? That is, pair up each term with a logical variable, the same term having the same var.


Solution

  • Can use:

    keys_keyvals(Ks, KVs) :-
        keys_keyvals_(Ks, [], KVs).
    
    keys_keyvals_([], _, []).
    keys_keyvals_([K|L], S, [K-V|R]) :-
        keys_keyvals_seen(S, K, V, S, S1),
        keys_keyvals_(L, S1, R).
    
    % End of list - add Key-Value pair to Seen list
    keys_keyvals_seen([], K, V, S, [K-V|S]).
    % Found match
    keys_keyvals_seen([H-X|_], K, V, S, S) :-
        (   H == K
        % Definite match, no need to keep looking
        ->  !
        ;   H = K
        ),
        % Unifying after cut
        X = V.
    % Keep looking
    keys_keyvals_seen([H-_|T], K, V, S, S1) :-
        dif(H, K),
        keys_keyvals_seen(T, K, V, S, S1).
    

    Result in swi-prolog:

    ?- keys_keyvals([a,b,a,b,c,b,c,d], KVs).
    KVs = [a-_A, b-_B, a-_A, b-_B, c-_C, b-_B, c-_C, d-_].
    

    This also handles the keys being var, e.g.:

    ?- keys_keyvals([a,b,b,c,X,X], KVs).
    X = c,
    KVs = [a-_, b-_A, b-_A, c-_B, c-_B, c-_B] ;
    X = b,
    KVs = [a-_, b-_A, b-_A, c-_, b-_A, b-_A] ;
    X = a,
    KVs = [a-_A, b-_B, b-_B, c-_, a-_A, a-_A] ;
    KVs = [a-_, b-_A, b-_A, c-_, X-_B, X-_B],
    dif(X, c),
    dif(X, a),
    dif(X, b).
    

    ... and it works in both directions, e.g.:

    ?- keys_keyvals(Ks, [a-A, b-B, a-X]).
    Ks = [a, b, a],
    A = X.