Did you know ... Search Documentation:
Pack canny_tudor -- prolog/swi/dicts.pl
PublicShow source
 put_dict(+Key, +Dict0:dict, +OnNotEmpty:callable, +Value, -Dict:dict) is det
Updates dictionary pair calling for merge if not empty. Updates Dict0 to Dict with Key-Value, combining Value with any existing value by calling OnNotEmpty/3. The callable can merge its first two arguments in some way, or replace the first with the second, or even reject the second.

The implementation puts Key and Value in Dict0, unifying the result at Dict. However, if the dictionary Dict0 already contains another value for the indicated Key then it invokes OnNotEmpty with the original Value0 and the replacement Value, finally putting the combined or selected Value_ in the dictionary for the Key.

 merge_dict(+Dict0:dict, +Dict1:dict, -Dict:dict) is semidet
Merges multiple pairs from a dictionary Dict1, into dictionary Dict0, unifying the results at Dict. Iterates the pairs for the Dict1 dictionary, using them to recursively update Dict0 key-by-key. Discards the tag from Dict1; Dict carries the same tag as Dict0.

Merges non-dictionaries according to type. Appends lists when the value in a key-value pair has list type. Only replaces existing values with incoming values when the leaf is not a dictionary, and neither existing nor incoming is a list.

Note the argument order. The first argument specifies the base dictionary starting point. The second argument merges into the first. The resulting merge unifies at the third argument. The order only matters if keys collide. Pairs from Dict1 replace key-matching pairs in Dict0.

Merging does not replace the original dictionary tag. This includes an unbound tag. The tag of Dict0 remains unchanged after merge.

 merge_pair(+Dict0:dict, +Pair:pair, -Dict:dict) is det
Merges Pair with dictionary. Merges a key-value Pair into dictionary Dict0, unifying the results at Dict.

Private predicate merge_dict_/3 is the value merging predicate; given the original Value0 and the incoming Value, it merges the two values at Value_.

 merge_dicts(+Dicts:list(dict), -Dict:dict) is semidet
Merges one or more dictionaries. You cannot merge an empty list of dictionaries. Fails in such cases. It does not unify Dict with a tagless empty dictionary. The implementation merges two consecutive dictionaries before tail recursion until eventually one remains.

Merging ignores tags.

 dict_member(?Dict:dict, ?Member) is nondet
Unifies with members of dictionary. Unifies Member with all dictionary members, where Member is any non-dictionary leaf, including list elements, or empty leaf dictionary.

Keys become tagged keys of the form Tag^Key. The caret operator neatly fits by operator precedence in-between the pair operator (-) and the sub-key slash delimiter (/). Nested keys become nested slash-functor binary compounds of the form TaggedKeys/TaggedKey. So for example, the compound Tag^Key-Value translates to Tag{Key:Value} in dictionary form. Tag^Key-Value decomposes term-wise as [-, Tag^Key, Value]. Note that tagged keys, including super-sub tagged keys, take precedence within the term.

This is a non-standard approach to dictionary unification. It turns nested sub-dictionary hierarchies into flatten pair-lists of tagged-key paths and their leaf values.

 dict_leaf(-Dict, +Pair) is semidet
dict_leaf(+Dict, -Pair) is nondet
Unifies Dict with its leaf nodes non-deterministically. Each Pair is either an atom for root-level keys, or a compound for nested-dictionary keys. Pair thereby represents a nested key path Leaf with its corresponding Value.

Fails for integer keys because integers cannot serve as functors. Does not attempt to map integer keys to an atom, since this will create a reverse conversion disambiguation issue. This does work for nested integer leaf keys, e.g. a(1), provided that the integer key does not translate to a functor.

Dict- is either a dictionary or a list of key-value pairs whose syntax conforms to valid dictionary data.
 dict_pair(+Dict, -Pair) is nondet
dict_pair(-Dict, +Pair) is det
Finds all dictionary pairs non-deterministically and recursively where each pair is a Path-Value. Path is a slash-delimited dictionary key path. Note, the search fails for dictionary leaves; succeeds only for non-dictionaries. Fails therefore for empty dictionaries or dictionaries of empty sub-dictionaries.
 findall_dict(?Tag, ?Template, :Goal, -Dicts:list(dict)) is det
Finds all dictionary-only solutions to Template within Goal. Tag selects which tags to select. What happens when Tag is variable? In such cases, unites with the first bound tag then all subsequent matching tags.
 dict_tag(+Dict, ?Tag) is semidet
Tags Dict with Tag if currently untagged. Fails if already tagged but not matching Tag, just like is_dict/2 with a ground tag. Never mutates ground tags as a result. Additionally Tags all nested sub-dictionaries using Tag and the sub-key for the sub-dictionary. An underscore delimiter concatenates the tag and key.

The implementation uses atomic concatenation to merge Tag and the dictionary sub-keys. Note that atomic_list_concat/3 works for non-atomic keys, including numbers and strings. Does not traverse sub-lists. Ignores sub-dictionaries where a dictionary value is a list containing dictionaries. Perhaps future versions will.

 create_dict(?Tag, +Dict0, -Dict) is semidet
Creates a dictionary just like dict_create/3 does but with two important differences. First, the argument order differs. Tag comes first to make maplist/3 and convlist/3 more convenient where the Goal argument includes the Tag. The new dictionary Dict comes last for the same reason. Secondly, always applies the given Tag to the new Dict, even if the incoming Data supplies one.

Creating a dictionary using standard dict_create/3 overrides the tag argument from its Data dictionary, ignoring the Tag if any. For example, using dict_create/3 for tag xyz and dictionary abc{} gives you abc{} as the outgoing dictionary. This predicate reverses this behaviour; the Tag argument replaces any tag in a Data dictionary.

 is_key(+Key:any) is semidet
Succeeds for terms that can serve as keys within a dictionary. Dictionary keys are atoms or tagged integers, otherwise known as constant values. Integers include negatives.
Key- successfully unites for all dictionary-key conforming terms: atomic or integral.
 dict_compound(+Dict:dict, ?Compound:compound) is nondet
Finds all compound-folded terms within Dict. Unifies with all pairs within Dict as compounds of the form key(Value) where key matches the dictionary key converted to one-two style and lower-case.

Unfolds lists and sub-dictionaries non-deterministically. For most occasions, the non-deterministic unfolding of sub-lists results in multiple non-deterministic solutions and typically has a plural compound name. This is not a perfect solution for lists of results, since the order of the solutions defines the relations between list elements.

Dictionary keys can be atoms or integers. Converts integers to compound names using integer-to-atom translation. However, compounds for sub-dictionaries re-wrap the sub-compounds by inserting the integer key as the prefix argument of a two or more arity compound.

 list_dict(?List, ?Tag, ?Dict) is semidet
List to Dict by zipping up items from List with integer indexed keys starting at 1. Finds only the first solution, even if multiple solutions exist.