%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  PDSS (PIMOS Development Support System)  Version 2.52		 %
%  (C) Copyright 1990,1991,1992.					 %
%  Institute for New Generation Computer Technology (ICOT), Japan.	 %
%  Read "../COPYRIGHT" for detailed information.			 %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

:- module merger.
:- with_macro pimos.
:- public merge/4,key_merge/4.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% merge(In,In1,Comparator,Out)
%%      In,In1  :: Input streams of the sorted data
%%      Comparator :: Code pointer to the user defined comparator module
%%      Out     :: Output stream of the sorted data

merge([X|Xs],[Y|Ys],ascending,Out) :- true |
        merge(Xs,Ys,X,Y,Out).
merge([X|Xs],[Y|Ys],descending,Out) :- true |
        merge_descending(Xs,Ys,X,Y,Out).
%merge([X|Xs],[Y|Ys],Comp,Out) :- code(Comp,_,_,_) |
merge([X|Xs],[Y|Ys],Comp,Out) :- builtin#code(Comp) |
        merge_user_defined(Xs,Ys,X,Y,Out,Comp).
merge([],Ys,_,Out) :- true | Ys=Out.
merge(Xs,[],_,Out) :- true | Xs=Out.
otherwise.
merge(Xs,Ys,_,Out) :- true |
        Out=[],
        if_raise_error(Xs),
        if_raise_error(Ys).

%*** merge ***
merge(Xs,Ys,X,Y,Out) :- X=<Y,Xs=[X1|Xs1] |
        Out=[X|Out1],
        merge(Xs1,Ys,X1,Y,Out1).
merge(Xs,Ys,X,Y,Out) :- X=<Y,Xs=[] |
        Out=[X,Y|Ys].
merge(Xs,Ys,X,Y,Out) :- X>Y,Ys=[Y1|Ys1] |
        Out=[Y|Out1],
        merge(Xs,Ys1,X,Y1,Out1).
merge(Xs,Ys,X,Y,Out) :- X>Y,Ys=[] |
        Out=[Y,X|Xs].
merge(Xs,Ys,X,Y,Out) :- X$=<Y,Xs=[X1|Xs1] |
        Out=[X|Out1],
        merge(Xs1,Ys,X1,Y,Out1).
merge(Xs,Ys,X,Y,Out) :- X$=<Y,Xs=[] |
        Out=[X,Y|Ys].
merge(Xs,Ys,X,Y,Out) :- X$>Y,Ys=[Y1|Ys1] |
        Out=[Y|Out1],
        merge(Xs,Ys1,X,Y1,Out1).
merge(Xs,Ys,X,Y,Out) :- X$>Y,Ys=[] |
        Out=[Y,X|Xs].
merge(Xs,Ys,X,Y,Out) :- atom(X),atom(Y),
    tag_and_value(X,_,U),tag_and_value(Y,_,V),U=<V,Xs=[X1|Xs1] |
        Out=[X|Out1],
        merge(Xs1,Ys,X1,Y,Out1).
merge(Xs,Ys,X,Y,Out) :- atom(X),atom(Y),
    tag_and_value(X,_,U),tag_and_value(Y,_,V),U=<V,Xs=[] |
        Out=[X,Y|Ys].
merge(Xs,Ys,X,Y,Out) :- atom(X),atom(Y),
    tag_and_value(X,_,U),tag_and_value(Y,_,V),U>V,Ys=[Y1|Ys1] |
        Out=[Y|Out1],
        merge(Xs,Ys1,X,Y1,Out1).
merge(Xs,Ys,X,Y,Out) :- atom(X),atom(Y),
    tag_and_value(X,_,U),tag_and_value(Y,_,V),U>V,Ys=[] |
        Out=[Y,X|Xs].
%merge(Xs,Ys,X,Y,Out) :- string_not_less_than(Y,X),Xs=[X1|Xs1] |
%        Out=[X|Out1],
%        merge(Xs1,Ys,X1,Y,Out1).
%merge(Xs,Ys,X,Y,Out) :- string_not_less_than(Y,X),Xs=[] |
%        Out=[X,Y|Ys].
%merge(Xs,Ys,X,Y,Out) :- string_less_than(Y,X),Ys=[Y1|Ys1] |
%        Out=[Y|Out1],
%        merge(Xs,Ys1,X,Y1,Out1).
%merge(Xs,Ys,X,Y,Out) :- string_less_than(Y,X),Ys=[] |
%        Out=[Y,X|Xs].
otherwise.
merge(Xs,Ys,X,Y,Out) :- true |
        comparator:sort0(X,Y,X1,Y1,Res),
        wait_comp(Xs,Ys,X1,Y1,Out,Res).

wait_comp(Xs,Ys,X,Y,Out,greater) :- Ys=[Y1|Ys1] |
        Out=[Y|Out1],
        merge(Xs,Ys1,X,Y1,Out1).
wait_comp(Xs,Ys,X,Y,Out,greater) :- Ys=[] |
        Out=[Y,X|Xs].
otherwise.
wait_comp(Xs,Ys,X,Y,Out,_) :- Xs=[X1|Xs1] |
        Out=[X|Out1],
        merge(Xs1,Ys,X1,Y,Out1).
wait_comp(Xs,Ys,X,Y,Out,_) :- Xs=[] |
        Out=[X,Y|Ys].

%*** merge_descending ***
merge_descending(Xs,Ys,X,Y,Out) :- X>=Y,Xs=[X1|Xs1] |
        Out=[X|Out1],
        merge_descending(Xs1,Ys,X1,Y,Out1).
merge_descending(Xs,Ys,X,Y,Out) :- X>=Y,Xs=[] |
        Out=[X,Y|Ys].
merge_descending(Xs,Ys,X,Y,Out) :- X<Y,Ys=[Y1|Ys1] |
        Out=[Y|Out1],
        merge_descending(Xs,Ys1,X,Y1,Out1).
merge_descending(Xs,Ys,X,Y,Out) :- X<Y,Ys=[] |
        Out=[Y,X|Xs].
merge_descending(Xs,Ys,X,Y,Out) :- X$>=Y,Xs=[X1|Xs1] |
        Out=[X|Out1],
        merge_descending(Xs1,Ys,X1,Y,Out1).
merge_descending(Xs,Ys,X,Y,Out) :- X$>=Y,Xs=[] |
        Out=[X,Y|Ys].
merge_descending(Xs,Ys,X,Y,Out) :- X$<Y,Ys=[Y1|Ys1] |
        Out=[Y|Out1],
        merge_descending(Xs,Ys1,X,Y1,Out1).
merge_descending(Xs,Ys,X,Y,Out) :- X$<Y,Ys=[] |
        Out=[Y,X|Xs].
merge_descending(Xs,Ys,X,Y,Out) :- atom(X),atom(Y),
    tag_and_value(X,_,U),tag_and_value(Y,_,V),U>=V,Xs=[X1|Xs1] |
        Out=[X|Out1],
        merge_descending(Xs1,Ys,X1,Y,Out1).
merge_descending(Xs,Ys,X,Y,Out) :- atom(X),atom(Y),
    tag_and_value(X,_,U),tag_and_value(Y,_,V),U>=V,Xs=[] |
        Out=[X,Y|Ys].
merge_descending(Xs,Ys,X,Y,Out) :- atom(X),atom(Y),
    tag_and_value(X,_,U),tag_and_value(Y,_,V),U<V,Ys=[Y1|Ys1] |
        Out=[Y|Out1],
        merge_descending(Xs,Ys1,X,Y1,Out1).
merge_descending(Xs,Ys,X,Y,Out) :- atom(X),atom(Y),
    tag_and_value(X,_,U),tag_and_value(Y,_,V),U<V,Ys=[] |
        Out=[Y,X|Xs].
%merge_descending(Xs,Ys,X,Y,Out) :- string_not_less_than(X,Y),Xs=[X1|Xs1] |
%        Out=[X|Out1],
%        merge_descending(Xs1,Ys,X1,Y,Out1).
%merge_descending(Xs,Ys,X,Y,Out) :- string_not_less_than(X,Y),Xs=[] |
%        Out=[X,Y|Ys].
%merge_descending(Xs,Ys,X,Y,Out) :- string_less_than(X,Y),Ys=[Y1|Ys1] |
%        Out=[Y|Out1],
%        merge_descending(Xs,Ys1,X,Y1,Out1).
%merge_descending(Xs,Ys,X,Y,Out) :- string_less_than(X,Y),Ys=[] |
%        Out=[Y,X|Xs].
otherwise.
merge_descending(Xs,Ys,X,Y,Out) :- true |
        comparator:sort0(X,Y,X1,Y1,Res),
        wait_comp_descending(Xs,Ys,X1,Y1,Out,Res).

wait_comp_descending(Xs,Ys,X,Y,Out,less) :- Ys=[Y1|Ys1] |
        Out=[Y|Out1],
        merge_descending(Xs,Ys1,X,Y1,Out1).
wait_comp_descending(Xs,Ys,X,Y,Out,less) :- Ys=[] |
        Out=[Y,X|Xs].
otherwise.
wait_comp_descending(Xs,Ys,X,Y,Out,_) :- Xs=[X1|Xs1] |
        Out=[X|Out1],
        merge_descending(Xs1,Ys,X1,Y,Out1).
wait_comp_descending(Xs,Ys,X,Y,Out,_) :- Xs=[] |
        Out=[X,Y|Ys].

%*** merge_user_defined ***
merge_user_defined(Xs,Ys,X,Y,Out,Comp) :- true |
        builtin#apply(Comp,{X,Y,Sml,Lag,YorN}),
        wait_comp_user_defined(Xs,Ys,Sml,Lag,Out,Comp,YorN).

wait_comp_user_defined(Xs,Ys,X,Y,Out,Comp,no) :- Xs=[X1|Xs1] |
        Out=[X|Out1],
        merge_user_defined(Xs1,Ys,X1,Y,Out1,Comp).
wait_comp_user_defined(Xs,Ys,X,Y,Out,_,no) :- Xs=[] |
        Out=[X,Y|Ys].
wait_comp_user_defined(Xs,Ys,Y,X,Out,Comp,yes) :- Ys=[Y1|Ys1] |
        Out=[Y|Out1],
        merge_user_defined(Xs,Ys1,X,Y1,Out1,Comp).
wait_comp_user_defined(Xs,Ys,Y,X,Out,_,yes) :- Ys=[] |
        Out=[Y,X|Xs].


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% key_merge(In,In1,Comparator,Out)
%%      In,In1  :: Input streams of the sorted data
%%      Comparator :: ascending/descending/Code pointer to the user defined comparator module
%%      Out     :: Output stream of the sorted data

key_merge([{K,D}|Xs],[{L,E}|Ys],ascending,Out) :- true |
        kmerge(Xs,Ys,K,L,Out,{_,D},{_,E}).
key_merge([{K,D}|Xs],[{L,E}|Ys],descending,Out) :- true |
        kmerge_descending(Xs,Ys,K,L,Out,{_,D},{_,E}).
%key_merge([{K,D}|Xs],[{L,E}|Ys],Comp,Out) :- code(Comp,_,_,_) |
key_merge([{K,D}|Xs],[{L,E}|Ys],Comp,Out) :- builtin#code(Comp) |
        kmerge_user_defined(Xs,Ys,K,L,Out,{_,D},{_,E},Comp).
key_merge([],Ys,_,Out) :- true | Ys=Out.
key_merge(Xs,[],_,Out) :- true | Xs=Out.
otherwise.
key_merge(Xs,Ys,_,Out) :- true |
        Out=[],
        if_raise_error(Xs),
        if_raise_error(Ys).

%*** kmerge ***
kmerge(Xs,Ys,K,L,Out,X,Y) :- K=<L,Xs=[{K1,D1}|Xs1],
    X={_,D} |
        Out=[{K,D}|Out1],
        kmerge(Xs1,Ys,K1,L,Out1,{_,D1},Y).
kmerge(Xs,Ys,K,L,Out,X,Y) :- K=<L,Xs=[],
    X={_,D},Y={_,E} |
        Out=[{K,D},{L,E}|Ys].
kmerge(Xs,Ys,K,L,Out,X,Y) :- K>L,Ys=[{L1,E1}|Ys1],
    Y={_,E} |
        Out=[{L,E}|Out1],
        kmerge(Xs,Ys1,K,L1,Out1,X,{_,E1}).
kmerge(Xs,Ys,K,L,Out,X,Y) :- K>L,Ys=[],
    X={_,D},Y={_,E} |
        Out=[{L,E},{K,D}|Xs].
kmerge(Xs,Ys,K,L,Out,X,Y) :- K$=<L,Xs=[{K1,D1}|Xs1],
    X={_,D} |
        Out=[{K,D}|Out1],
        kmerge(Xs1,Ys,K1,L,Out1,{_,D1},Y).
kmerge(Xs,Ys,K,L,Out,X,Y) :- K$=<L,Xs=[],
    X={_,D},Y={_,E} |
        Out=[{K,D},{L,E}|Ys].
kmerge(Xs,Ys,K,L,Out,X,Y) :- K$>L,Ys=[{L1,E1}|Ys1],
    Y={_,E} |
        Out=[{L,E}|Out1],
        kmerge(Xs,Ys1,K,L1,Out1,X,{_,E1}).
kmerge(Xs,Ys,K,L,Out,X,Y) :- K$>L,Ys=[],
    X={_,D},Y={_,E} |
        Out=[{L,E},{K,D}|Xs].
kmerge(Xs,Ys,K,L,Out,X,Y) :- atom(K),atom(L),
    tag_and_value(K,_,U),tag_and_value(L,_,V),U=<V,Xs=[{K1,D1}|Xs1],
    X={_,D} |
        Out=[{K,D}|Out1],
        kmerge(Xs1,Ys,K1,L,Out1,{_,D1},Y).
kmerge(Xs,Ys,K,L,Out,X,Y) :- atom(K),atom(L),
    tag_and_value(K,_,U),tag_and_value(L,_,V),U=<V,Xs=[],
    X={_,D},Y={_,E} |
        Out=[{K,D},{L,E}|Ys].
kmerge(Xs,Ys,K,L,Out,X,Y) :- atom(K),atom(L),
    tag_and_value(K,_,U),tag_and_value(L,_,V),U>V,Ys=[{L1,E1}|Ys1],
    Y={_,E} |
        Out=[{L,E}|Out1],
        kmerge(Xs,Ys1,K,L1,Out1,X,{_,E1}).
kmerge(Xs,Ys,K,L,Out,X,Y) :- atom(K),atom(L),
    tag_and_value(K,_,U),tag_and_value(L,_,V),U>V,Ys=[],
    X={_,D},Y={_,E} |
        Out=[{L,E},{K,D}|Xs].
%kmerge(Xs,Ys,K,L,Out,X,Y) :- string_not_less_than(L,K),Xs=[{K1,D1}|Xs1],
%    X={_,D} |
%        Out=[{K,D}|Out1],
%        kmerge(Xs1,Ys,K1,L,Out1,{_,D1},Y).
%kmerge(Xs,Ys,K,L,Out,X,Y) :- string_not_less_than(L,K),Xs=[],
%    X={_,D},Y={_,E} |
%        Out=[{K,D},{L,E}|Ys].
%kmerge(Xs,Ys,K,L,Out,X,Y) :- string_less_than(L,K),Ys=[{L1,E1}|Ys1],
%    Y={_,E} |
%        Out=[{L,E}|Out1],
%        kmerge(Xs,Ys1,K,L1,Out1,X,{_,E1}).
%kmerge(Xs,Ys,K,L,Out,X,Y) :- string_less_than(L,K),Ys=[],
%    X={_,D},Y={_,E} |
%        Out=[{L,E},{K,D}|Xs].

otherwise.
kmerge(Xs,Ys,K,L,Out,X,Y) :- true |
        comparator:sort0(K,L,K1,L1,Res),
        wait_kcomp(Xs,Ys,K1,L1,Out,X,Y,Res).

wait_kcomp(Xs,Ys,K,L,Out,X,Y,less) :- Xs=[{K1,D1}|Xs1],
    X={_,D} |
        Out=[{K,D}|Out1],
        kmerge(Xs1,Ys,K1,L,Out1,{_,D1},Y).
wait_kcomp(Xs,Ys,K,L,Out,X,Y,less) :- Xs=[],
    X={_,D},Y={_,E} |
        Out=[{K,D},{L,E}|Ys].
wait_kcomp(Xs,Ys,K,L,Out,X,Y,same) :- Xs=[{K1,D1}|Xs1],
    X={_,D} |
        Out=[{K,D}|Out1],
        kmerge(Xs1,Ys,K1,L,Out1,{_,D1},Y).
wait_kcomp(Xs,Ys,K,L,Out,X,Y,same) :- Xs=[],
    X={_,D},Y={_,E} |
        Out=[{K,D},{L,E}|Ys].
wait_kcomp(Xs,Ys,K,L,Out,X,Y,greater) :- Ys=[{L1,E1}|Ys1],
    Y={_,E} |
        Out=[{L,E}|Out1],
        kmerge(Xs,Ys1,K,L1,Out1,X,{_,E1}).
wait_kcomp(Xs,Ys,K,L,Out,X,Y,greater) :- Ys=[],
    X={_,D},Y={_,E} |
        Out=[{L,E},{K,D}|Xs].
otherwise.
wait_kcomp(Xs,Ys,_,_,Out,_,_,_) :- true |
        Out=[],
        if_raise_error(Xs),
        if_raise_error(Ys).

%*** kmerge_descending ***
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- K>=L,Xs=[{K1,D1}|Xs1],
    X={_,D} |
        Out=[{K,D}|Out1],
        kmerge_descending(Xs1,Ys,K1,L,Out1,{_,D1},Y).
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- K>=L,Xs=[],
    X={_,D},Y={_,E} |
        Out=[{K,D},{L,E}|Ys].
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- K<L,Ys=[{L1,E1}|Ys1],
    Y={_,E} |
        Out=[{L,E}|Out1],
        kmerge_descending(Xs,Ys1,K,L1,Out1,X,{_,E1}).
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- K<L,Ys=[],
    X={_,D},Y={_,E} |
        Out=[{L,E},{K,D}|Xs].
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- K$>=L,Xs=[{K1,D1}|Xs1],
    X={_,D} |
        Out=[{K,D}|Out1],
        kmerge_descending(Xs1,Ys,K1,L,Out1,{_,D1},Y).
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- K$>=L,Xs=[],
    X={_,D},Y={_,E} |
        Out=[{K,D},{L,E}|Ys].
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- K$<L,Ys=[{L1,E1}|Ys1],
    Y={_,E} |
        Out=[{L,E}|Out1],
        kmerge_descending(Xs,Ys1,K,L1,Out1,X,{_,E1}).
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- K$<L,Ys=[],
    X={_,D},Y={_,E} |
        Out=[{L,E},{K,D}|Xs].
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- atom(K),atom(L),
    tag_and_value(K,_,U),tag_and_value(L,_,V),U>=V,Xs=[{K1,D1}|Xs1],
    X={_,D} |
        Out=[{K,D}|Out1],
        kmerge_descending(Xs1,Ys,K1,L,Out1,{_,D1},Y).
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- atom(K),atom(L),
    tag_and_value(K,_,U),tag_and_value(L,_,V),U>=V,Xs=[],
    X={_,D},Y={_,E} |
        Out=[{K,D},{L,E}|Ys].
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- atom(K),atom(L),
    tag_and_value(K,_,U),tag_and_value(L,_,V),U<V,Ys=[{L1,E1}|Ys1],
    Y={_,E} |
        Out=[{L,E}|Out1],
        kmerge_descending(Xs,Ys1,K,L1,Out1,X,{_,E1}).
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- atom(K),atom(L),
    tag_and_value(K,_,U),tag_and_value(L,_,V),U<V,Ys=[],
    X={_,D},Y={_,E} |
        Out=[{L,E},{K,D}|Xs].
%kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- string_not_less_than(K,L),Xs=[{K1,D1}|Xs1],
%    X={_,D} |
%        Out=[{K,D}|Out1],
%        kmerge_descending(Xs1,Ys,K1,L,Out1,{_,D1},Y).
%kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- string_not_less_than(K,L),Xs=[],
%    X={_,D},Y={_,E} |
%        Out=[{K,D},{L,E}|Ys].
%kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- string_less_than(K,L),Ys=[{L1,E1}|Ys1],
%    Y={_,E} |
%        Out=[{L,E}|Out1],
%        kmerge_descending(Xs,Ys1,K,L1,Out1,X,{_,E1}).
%kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- string_less_than(K,L),Ys=[],
%    X={_,D},Y={_,E} |
%        Out=[{L,E},{K,D}|Xs].
otherwise.
kmerge_descending(Xs,Ys,K,L,Out,X,Y) :- true |
        comparator:sort0(K,L,K1,L1,Res),
        wait_kcomp_descending(Xs,Ys,K1,L1,Out,X,Y,Res).

wait_kcomp_descending(Xs,Ys,K,L,Out,X,Y,greater) :- Xs=[{K1,D1}|Xs1],
    X={_,D} |
        Out=[{K,D}|Out1],
        kmerge_descending(Xs1,Ys,K1,L,Out1,{_,D1},Y).
wait_kcomp_descending(Xs,Ys,K,L,Out,X,Y,greater) :- Xs=[],
    X={_,D},Y={_,E} |
        Out=[{K,D},{L,E}|Ys].
wait_kcomp_descending(Xs,Ys,K,L,Out,X,Y,same) :- Xs=[{K1,D1}|Xs1],
    X={_,D} |
        Out=[{K,D}|Out1],
        kmerge_descending(Xs1,Ys,K1,L,Out1,{_,D1},Y).
wait_kcomp_descending(Xs,Ys,K,L,Out,X,Y,same) :- Xs=[],
    X={_,D},Y={_,E} |
        Out=[{K,D},{L,E}|Ys].
wait_kcomp_descending(Xs,Ys,K,L,Out,X,Y,less) :- Ys=[{L1,E1}|Ys1],
    Y={_,E} |
        Out=[{L,E}|Out1],
        kmerge_descending(Xs,Ys1,K,L1,Out1,X,{_,E1}).
wait_kcomp_descending(Xs,Ys,K,L,Out,X,Y,less) :- Ys=[],
    X={_,D},Y={_,E} |
        Out=[{L,E},{K,D}|Xs].
otherwise.
wait_kcomp_descending(Xs,Ys,_,_,Out,_,_,_) :- true |
        Out=[],
        if_raise_error(Xs),
        if_raise_error(Ys).

%*** kmerge_user_defined ***
kmerge_user_defined(Xs,Ys,K,L,Out,X,Y,Comp) :- true |
        builtin#apply(Comp,{K,L,Sml,Lag,YorN}),
        wait_kcomp_user_defined(Xs,Ys,Sml,Lag,Out,X,Y,Comp,YorN).

wait_kcomp_user_defined(Xs,Ys,K,L,Out,X,Y,Comp,no) :- Xs=[{K1,D1}|Xs1],
    X={_,D} |
        Out=[{K,D}|Out1],
        kmerge_user_defined(Xs1,Ys,K1,L,Out1,{_,D1},Y,Comp).
wait_kcomp_user_defined(Xs,Ys,K,L,Out,X,Y,_,no) :- Xs=[],
    X={_,D},Y={_,E} |
        Out=[{K,D},{L,E}|Ys].
wait_kcomp_user_defined(Xs,Ys,L,K,Out,X,Y,Comp,yes) :- Ys=[{L1,E1}|Ys1],
    Y={_,E} |
        Out=[{L,E}|Out1],
        kmerge_user_defined(Xs,Ys1,K,L1,Out1,X,{_,E1},Comp).
wait_kcomp_user_defined(Xs,Ys,L,K,Out,X,Y,_,yes) :- Ys=[],
    X={_,D},Y={_,E} |
        Out=[{L,E},{K,D}|Xs].
otherwise.
wait_kcomp_user_defined(Xs,Ys,_,_,Out,_,_,_,_) :- true |
        Out=[],
        if_raise_error(Xs),
        if_raise_error(Ys).


if_raise_error([X|_]) :- true |
        if_raise_error_data_protocol(X).
otherwise.
if_raise_error(X) :- true |
%        shoen:raise(pimos_tag#error,
        raise(pimos_tag#error,
            '$PIMOS$'(key_merge,string#"illegal_protocol"),X).

if_raise_error_data_protocol({_,_}) :- true | true.
otherwise.
if_raise_error_data_protocol(X) :- true |
%        shoen:raise(pimos_tag#error,
        raise(pimos_tag#error,
            '$PIMOS$'(key_merge,string#"illegal_data_protocol"),X).


