How about using self-balancing red-black trees? SWI-Prolog includes library(rbtrees)
.
Use it together with iwhen/2
to safeguard against insufficient instantiation like so:
:- use_module(library(rbtrees)).
assoc_to_rb(Ps, T) :-
iwhen(ground(Ps), groundassoc_to_rb(Ps,T)).
groundassoc_to_rb(Ps0, T) :-
keysort(Ps0, Ps),
( append(_, [K-_,K-_|_], Ps)
-> throw(error(domain_error(unique_keyed_assoc,Ps0),_))
; list_to_rbtree(Ps, T)
).
Sample queries using SWI-Prolog 8.0.0:
?- assoc_to_rb([three-3,two-2,one-1,four-4], T), rb_in(four,Value,T).
T = t(black('', _7860, _7862, ''), black(black(black('', _7860, _7862, ''), four, 4, black('', _7860, _7862, '')), one, 1, black(black('', _7860, _7862, ''), three, 3, red(black('', _7860, _7862, ''), two, 2, black('', _7860, _7862, ''))))), Value = 4
; false.
?- assoc_to_rb([3-three,2-two,1-one,4-four,4-vier], T).
ERROR: Domain error: `unique_keyed_assoc' expected, found `[3-three,2-two,1-one,4-four,4-vier]'