:- prompt(_, '').
:- use_module(library(readutil)).
% unify finite maps
unify_map(A,B) :- submap_of(A,B), submap_of(B,A).
submap_of([], _).
submap_of([X:V|R],M) :- first(X:V,M), submap_of(R,M).
% search key and find value in a finite map
first(X:V,[X:V|_]).
first(X:V,[Y:_|L]) :- X \== Y, first(X:V,L).
% finite map minus
mapminus(A,[],A).
mapminus([],_,[]).
mapminus
([X
:V
|Ps
],B
,C
) :- first
(X
:V1
,B
), !, (V1
= V
-> mapminus
(Ps
,B
,C
); fail).mapminus([X:V|Ps],B,[X:V|C]) :- mapminus(Ps,B,C).
% unify open ended maps with possibly uninstantiated variable tail at the end
unify_oemap
(A
,B
) :- ( var(A
); var(B
) ), !, A
=B
.unify_oemap(A,B) :-
split_heads(A,Xs-T1), make_map(Xs,M1),
split_heads(B,Ys-T2), make_map(Ys,M2),
unify_oe_map(M1-T1, M2-T2).
make_map
(L
,M
) :- setof(X
:V
,first
(X
:V
,L
),M
). % unlike sets this may not remove duplicates
split_heads([],[]-[]).
split_heads
([X
:V
|T
],[X
:V
]-T
) :- var(T
), !, true.split_heads([X:V|Ps],[X:V|Hs]-T) :- split_heads(Ps,Hs-T).
% helper function for unify_oemap
unify_oe_map(Xs-T1,Ys-T2) :- T1==[], T2==[], unify_map(Xs,Ys).
unify_oe_map(Xs-T1,Ys-T2) :- T1==[], submap_of(Ys,Xs), mapminus(Xs,Ys,T2).
unify_oe_map(Xs-T1,Ys-T2) :- T2==[], submap_of(Xs,Ys), mapminus(Ys,Xs,T1).
unify_oe_map(Xs-T1,Ys-T2) :-
mapminus(Ys,Xs,L1), append(L1,T,T1),
mapminus(Xs,Ys,L2), append(L2,T,T2).
main:-
process,
process:-
unify_oemap([z:string,y:bool|M1],[y:T,x:int|M2]),
:- main.
Oi0gc2V0X3Byb2xvZ19mbGFnKHZlcmJvc2Usc2lsZW50KS4KOi0gcHJvbXB0KF8sICcnKS4KOi0gdXNlX21vZHVsZShsaWJyYXJ5KHJlYWR1dGlsKSkuCgolIHVuaWZ5IGZpbml0ZSBtYXBzCnVuaWZ5X21hcChBLEIpIDotIHN1Ym1hcF9vZihBLEIpLCBzdWJtYXBfb2YoQixBKS4KCnN1Ym1hcF9vZihbXSwgXykuCnN1Ym1hcF9vZihbWDpWfFJdLE0pIDotIGZpcnN0KFg6VixNKSwgc3VibWFwX29mKFIsTSkuCgolIHNlYXJjaCBrZXkgYW5kIGZpbmQgdmFsdWUgaW4gYSBmaW5pdGUgbWFwCmZpcnN0KFg6VixbWDpWfF9dKS4KZmlyc3QoWDpWLFtZOl98TF0pIDotIFggXD09IFksIGZpcnN0KFg6VixMKS4KCiUgZmluaXRlIG1hcCBtaW51cwptYXBtaW51cyhBLFtdLEEpLgptYXBtaW51cyhbXSxfLFtdKS4KbWFwbWludXMoW1g6VnxQc10sQixDKSA6LSBmaXJzdChYOlYxLEIpLCAhLCAoVjEgPSBWIC0+IG1hcG1pbnVzKFBzLEIsQyk7IGZhaWwpLgptYXBtaW51cyhbWDpWfFBzXSxCLFtYOlZ8Q10pIDotIG1hcG1pbnVzKFBzLEIsQykuCgoKJSB1bmlmeSBvcGVuIGVuZGVkIG1hcHMgd2l0aCBwb3NzaWJseSB1bmluc3RhbnRpYXRlZCB2YXJpYWJsZSB0YWlsIGF0IHRoZSBlbmQKdW5pZnlfb2VtYXAoQSxCKSA6LSAoIHZhcihBKTsgdmFyKEIpICksICEsIEE9Qi4KdW5pZnlfb2VtYXAoQSxCKSA6LQoJc3BsaXRfaGVhZHMoQSxYcy1UMSksIG1ha2VfbWFwKFhzLE0xKSwKCXNwbGl0X2hlYWRzKEIsWXMtVDIpLCBtYWtlX21hcChZcyxNMiksCgl1bmlmeV9vZV9tYXAoTTEtVDEsIE0yLVQyKS4KCm1ha2VfbWFwKEwsTSkgOi0gc2V0b2YoWDpWLGZpcnN0KFg6VixMKSxNKS4gJSB1bmxpa2Ugc2V0cyB0aGlzIG1heSBub3QgcmVtb3ZlIGR1cGxpY2F0ZXMKCnNwbGl0X2hlYWRzKFtdLFtdLVtdKS4Kc3BsaXRfaGVhZHMoW1g6VnxUXSxbWDpWXS1UKSA6LSB2YXIoVCksICEsIHRydWUuCnNwbGl0X2hlYWRzKFtYOlZ8UHNdLFtYOlZ8SHNdLVQpIDotIHNwbGl0X2hlYWRzKFBzLEhzLVQpLgoKJSBoZWxwZXIgZnVuY3Rpb24gZm9yIHVuaWZ5X29lbWFwCnVuaWZ5X29lX21hcChYcy1UMSxZcy1UMikgOi0gVDE9PVtdLCBUMj09W10sIHVuaWZ5X21hcChYcyxZcykuCnVuaWZ5X29lX21hcChYcy1UMSxZcy1UMikgOi0gVDE9PVtdLCBzdWJtYXBfb2YoWXMsWHMpLCBtYXBtaW51cyhYcyxZcyxUMikuCnVuaWZ5X29lX21hcChYcy1UMSxZcy1UMikgOi0gVDI9PVtdLCBzdWJtYXBfb2YoWHMsWXMpLCBtYXBtaW51cyhZcyxYcyxUMSkuCnVuaWZ5X29lX21hcChYcy1UMSxZcy1UMikgOi0gCgltYXBtaW51cyhZcyxYcyxMMSksIGFwcGVuZChMMSxULFQxKSwKCW1hcG1pbnVzKFhzLFlzLEwyKSwgYXBwZW5kKEwyLFQsVDIpLgoKCm1haW46LQoJcHJvY2VzcywKCWhhbHQuCgpwcm9jZXNzOi0KCXVuaWZ5X29lbWFwKFt6OnN0cmluZyx5OmJvb2x8TTFdLFt5OlQseDppbnR8TTJdKSwKCXdyaXRlKCJUID0gIiksIHByaW50KFQpLCBubCwKCXdyaXRlKCJNMSA9ICIpLCBwcmludChNMSksIG5sLAoJd3JpdGUoIk0yID0gIiksIHByaW50KE0yKSwgbmwsCgl0cnVlLgoKOi0gbWFpbi4=