1:- module(
    2  dict,
    3  [
    4    dict_change_keys/3,  % +Dict1, +KeyChanges, -Dict2
    5    dict_delete/3,       % +KeyOrKeys, +From, -To
    6    dict_delete/4,       % +Key, +From, -Value, -To
    7    dict_delete/5,       % +Key, +From, +Default, -Value, -To
    8    dict_get/3,          % ?KeyOrKeys, +Dict, -Value
    9    dict_get/4,          % +KeyOrKeys, +Dict, +Default, -Value
   10    dict_inc/2,          % +Key, +Dict
   11    dict_inc/3,          % +Key, +Dict, -Value
   12    dict_inc/4,          % +Key, +Dict, +Diff, -Value
   13    dict_key/2,          % +Dict, ?Key
   14    dict_pairs/2,        % ?Dict, ?Pairs
   15    dict_put/3,          % +From1, +From2, -To
   16    dict_put/4,          % +Key, +From, +Value, -To
   17    dict_select/3,       % +Select, +From, -To
   18    dict_select/4,       % +Key, +From, -To, -Value
   19    dict_select/5,       % +Key, +From, +Default, -To, -Value
   20    dict_tag/2,          % +Dict, ?Tag
   21    dict_tag/3,          % +From, ?Tag, -To
   22    dict_terms/2,        % ?Dict, ?Terms
   23    merge_dicts/2,       % +Froms, -To
   24    merge_dicts/3,       % +NewFrom, +OldFrom, -To
   25    nb_increment_dict/2, % +Dict, +Key
   26    nb_increment_dict/3  % +Dict, +Key, -Value
   27  ]
   28).

Dictionary extension

*/

   34:- use_module(library(apply)).   35:- use_module(library(error)).   36:- use_module(library(lists)).   37
   38:- use_module(library(pair_ext)).
 dict_change_keys(+Dict1:dict, +KeyChanges:list(pair(atom)), -Dict2:dict) is det
   44dict_change_keys(Dict1, Changes, Dict2) :-
   45  dict_pairs(Dict1, Pairs1),
   46  change_keys(Pairs1, Changes, Pairs2),
   47  dict_pairs(Dict2, Pairs2).
 dict_delete(+KeyOrKeys:or([atom,list(atom)]), +From:dict, -To:dict) is det
   53dict_delete(Key, From, To) :-
   54  atom(Key), !,
   55  del_dict(Key, From, _, To).
   56dict_delete([], Dict, Dict) :- !.
   57dict_delete([H|T], Dict1, Dict3) :-
   58  del_dict(H, Dict1, _, Dict2),
   59  dict_delete(T, Dict2, Dict3).
 dict_delete(+Key:atom, +From:dict, -Value:term, -To:dict) is det
 dict_delete(+Key:atom, +From:dict, +Default:term, -Value:term, -To:dict) is det
Either delete the Value for Key from From resulting in To, or return the Default value and leave the dictionary unchanged.
   69dict_delete(Key, From, Value, To) :-
   70  del_dict(Key, From, Value, To).
   71
   72
   73dict_delete(Key, From, _, Value, To) :-
   74  del_dict(Key, From, Value, To), !.
   75dict_delete(_, Dict, Value, Value, Dict).
 dict_get(+KeyOrKeys:or([atom,list(atom)]), +Dict:dict, -Value:term) is semidet
dict_get(-Key:atom, +Dict:dict, -Value:term) is nondet
   82dict_get(Key, Dict, Value) :-
   83  var(Key), !,
   84  get_dict(Key, Dict, Value).
   85dict_get(Key, Dict, Value) :-
   86  atom(Key), !,
   87  dict_get_([Key], Dict, Value).
   88dict_get(Keys, Dict, Value) :-
   89  dict_get_(Keys, Dict, Value).
   90
   91dict_get_([], Value, Value) :- !.
   92dict_get_([H|T], Dict1, Value) :-
   93  get_dict(H, Dict1, Dict2),
   94  dict_get_(T, Dict2, Value).
   95
   96
   97dict_get(Keys, Dict, _, Value2) :-
   98  dict_get(Keys, Dict, Value1), !,
   99  Value2 = Value1.
  100dict_get(_, _, Value, Value).
 dict_inc(+Key:atom, +Dict:dict) is det
 dict_inc(+Key:atom, +Dict:dict, -Value:number) is det
 dict_inc(+Key:atom, +Dict:dict, +Diff:number, -Value:number) is det
  108dict_inc(Key, Dict) :-
  109  dict_inc(Key, Dict, _).
  110
  111
  112dict_inc(Key, Dict, Value) :-
  113  dict_inc(Key, Dict, 1, Value).
  114
  115
  116dict_inc(Key, Dict, Diff, Value2) :-
  117  get_dict(Key, Dict, Value1),
  118  Value2 is Value1 + Diff,
  119  nb_set_dict(Key, Dict, Value2).
 dict_key(+Dict:dict, +Key:atom) is semidet
dict_key(+Dict:dict, -Key:atom) is nondet
  126dict_key(Dict, Key) :-
  127  get_dict(Key, Dict, _).
 dict_pairs(+Dict:dict, +Pairs:list(pair(atom,term))) is semidet
dict_pairs(+Dict:dict, -Pairs:list(pair(atom,term))) is det
dict_pairs(-Dict:dict, +Pairs:list(pair(atom,term))) is det
  135dict_pairs(Dict, Pairs):-
  136  dict_pairs(Dict, _, Pairs).
 dict_put(+From1:dict, +From2:dict, -To:dict) is det
  142dict_put(From1, From2, To) :-
  143  To = From1.put(From2).
 dict_put(+Key:atom, +From:dict, +Value:term, -To:dict) is det
  149dict_put(Key, From, Value, To) :-
  150  put_dict(Key, From, Value, To).
 dict_select(+Select:dict, +From:dict, -To:dict) is det
  156dict_select(Select, From, To) :-
  157  select_dict(Select, From, To).
 dict_select(+Key:atom, +From:dict, -To:dict, -Value:term) is semidet
 dict_select(+Key:atom, +From:dict, +Default:term, -To:dict, -Value:term) is det
  164dict_select(Key, From, To, Value) :-
  165  dict_pairs(Select, [Key-Value]),
  166  select_dict(Select, From, To), !.
  167
  168
  169dict_select(Key, From, _, To, Value) :-
  170  dict_select(Key, From, To, Value), !.
  171dict_select(_, Dict, Value, Dict, Value).
 dict_tag(+Dict:dict, +Tag:atom) is semidet
dict_tag(+Dict:dict, -Tag:atom) is det
  178dict_tag(Dict, Tag) :-
  179  dict_pairs(Dict, Tag, _).
 dict_tag(+From:dict, +Tag:atom, +To:dict) is semidet
dict_tag(+From:dict, +Tag:atom, -To:dict) is det
Converts between dictionaries that differ only in their outer tag name.
  187dict_tag(From, Tag, To):-
  188  dict_pairs(From, _, Pairs),
  189  dict_pairs(To, Tag, Pairs).
 dict_terms(+Dict:dict, -Terms:list(compound)) is det
dict_terms(-Dict:dict, +Terms:list(compound)) is det
  196dict_terms(Dict, Terms) :-
  197  var(Terms), !,
  198  dict_pairs(Dict, Pairs),
  199  maplist(compound_pair, Terms, Pairs).
  200dict_terms(Dict, Terms) :-
  201  maplist(compound_pair, Terms, Pairs),
  202  dict_pairs(Dict, Pairs).
  203dict_terms(Dict, Pairs) :-
  204  instantiation_error([Dict,Pairs]).
 merge_dicts(+Dicts:list(dict), -Dict:dict) is det
A string of applications of merge_dicts/3, where newer dictionaries appear later in `Dicts'.
  213merge_dicts([], []).
  214merge_dicts([H], H) :- !.
  215merge_dicts([H1,H2|T1], T2) :-
  216  merge_dicts(H2, H1, H12),
  217  merge_dicts([H12|T1], T2).
 merge_dicts(+NewFrom:dict, +OldFrom:dict, -To:dict) is det
Merges two dictionaries into one new dictionary, similar to merge_options/3 from the `option' standard library.

If NewFrom and OldFrom contain the same key then the value from NewFrom is used, unless both are dicts, in which case the dicts are merged recursively. If NewFrom and OldFrom have a different tag, then the tag from NewFrom is used.

  230merge_dicts(NewFrom, OldFrom, To):-
  231  dict_pairs(NewFrom, Tag, NewPairs0),
  232  dict_pairs(OldFrom, _, OldPairs0),
  233  maplist(sort(1, @<), [OldPairs0,NewPairs0], [OldPairs,NewPairs]),
  234  merge_pairs(NewPairs, OldPairs, Pairs),
  235  dict_pairs(To, Tag, Pairs).
 nb_increment_dict(+Dict:dict, +Key:atom) is det
 nb_increment_dict(+Dict:dict, +Key:atom, -Value:positive_integer) is det
  242nb_increment_dict(Dict, Key) :-
  243  nb_increment_dict(Dict, Key, _).
  244
  245
  246nb_increment_dict(Dict, Key, N2) :-
  247  get_dict(Key, Dict, N1),
  248  N2 is N1 + 1,
  249  nb_set_dict(Key, Dict, N2)