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