/** Reasoning about pairs.

    Pairs are Prolog terms with principal functor `(-)/2`. A pair
    often has the form `Key-Value`. The predicates of this library
    relate pairs to keys and values.
*/

:- module(pairs, [pairs_keys_values/3,
		  pairs_keys/2,
		  pairs_values/2,
		  group_pairs_by_key/2,
		  map_list_to_pairs/3]).


:- meta_predicate(map_list_to_pairs(2, ?, ?)).

%% pairs_keys_values(?Pairs, ?Keys, ?Values)
%
%  The first argument is a list of Pairs, the second the corresponding
%  Keys, and the third argument the corresponding values.

pairs_keys_values([], [], []).
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
        pairs_keys_values(ABs, As, Bs).

%% pairs_keys(?Pairs, ?Keys)
%
%  Same as `pairs_keys_values(Pairs, Keys, _)`.

pairs_keys(Ps, Ks) :- pairs_keys_values(Ps, Ks, _).

%% pairs_values(?Pairs, ?Values)
%
%  Same as `pairs_keys_values(Pairs, _, Values)`.

pairs_values(Ps, Vs) :- pairs_keys_values(Ps, _, Vs).

map_list_to_pairs(Pred, Ls, Ps) :-
        map_list_to_pairs2(Ls, Pred, Ps).

map_list_to_pairs2([], _, []).
map_list_to_pairs2([H|T0], Pred, [K-H|T]) :-
        call(Pred, H, K),
        map_list_to_pairs2(T0, Pred, T).


group_pairs_by_key([], []).
group_pairs_by_key([K-V|KVs0], [K-[V|Vs]|KVs]) :-
        same_key(K, KVs0, Vs, KVs1),
        group_pairs_by_key(KVs1, KVs).

same_key(K0, [K1-V|KVs0], [V|Vs], KVs) :-
        K0 == K1, !,
        same_key(K0, KVs0, Vs, KVs).
same_key(_, KVs, [], KVs).
