The infix operator dot (op(100, yfx, .)
is used to
extract values and evaluate functions on dicts. Functions are recognised
if they appear in the argument of a goal in the source text,
possibly nested in a term. The keys act as field selector, which is
illustrated in this example.
?- X = point{x:1,y:2}.x.
X = 1.
?- Pt = point{x:1,y:2}, write(Pt.y).
2
Pt = point{x:1,y:2}.
?- X = point{x:1,y:2}.C.
X = 1,
C = x ;
X = 2,
C = y.
The compiler translates a goal that contains .
/2
terms in its arguments into a conjunction of calls to ./3
defined in the
system
module. Terms functor.
2 that appears in
the head are replaced with a variable and calls to ./3
are inserted at the start of the body. Below are two examples, where the
first extracts the
x
key from a dict and the second extends a dict containing
an address with the postal code, given a find_postal_code/4 predicate.
dict_x(X, X.x).
add_postal_code(Dict, Dict.put(postal_code, Code)) :-
find_postal_code(Dict.city,
Dict.street,
Dict.house_number,
Code).
Note that expansion of .
/2
terms implies
that such terms cannot be created by writing them explicitly in your
source code. Such terms can still be created with functor/3, =../2,
compound_name_arity/3
and
compound_name_arguments/3.180Traditional
code is unlikely to use .
/2
terms because they
were practically reserved for usage in lists. We do not provide a
quoting mechanism as found in functional languages because it would only
be needed to quote .
/2
terms, such terms are
rare and term manipulation provides an escape route.
- .(+Dict, +Function,
-Result)
- This predicate is called to evaluate
.
/2
terms
found in the arguments of a goal. This predicate evaluates the field
extraction described above, raising an exception if Function
is an atom (key) and Dict does not contain the
requested key. If Function is a compound term, it checks for
the predefined functions on dicts described in section
5.4.1.2 or executes a user defined function as described in
section 5.4.1.1.
The tag of a dict associates the dict to a module. If the dot
notation uses a compound term, this calls the goal below.
<module>:<name>(Arg1, ..., +Dict,
-Value)
Functions are normal Prolog predicates. The dict infrastructure
provides a more convenient syntax for representing the head of such
predicates without worrying about the argument calling conventions. The
code below defines a function multiply(Times)
on a point
that creates a new point by multiplying both coordinates. and len
181as length
would result in a predicate length/2,
this name cannot be used. This might change in future versions.
to compute the length from the origin. The . and :=
operators are used to abstract the location of the predicate arguments.
It is allowed to define multiple a function with multiple clauses,
providing overloading and non-determinism.
:- module(point, []).
M.multiply(F) := point{x:X, y:Y} :-
X is M.x*F,
Y is M.y*F.
M.len() := Len :-
Len is sqrt(M.x**2 + M.y**2).
After these definitions, we can evaluate the following functions:
?- X = point{x:1, y:2}.multiply(2).
X = point{x:2, y:4}.
?- X = point{x:1, y:2}.multiply(2).len().
X = 4.47213595499958.
Dicts currently define the following reserved functions:
- get(?KeyPath)
- Return the value associates with KeyPath. KeyPath
is either a single key or a term
Key1/Key2/...
. Each key is
either an atom, small integer or a variable. While Dict.Key
throws an existence error, this function fails silently if a
key does not exist in the target dict. See also :</2,
which can be used to test for existence and unify multiple key values
from a dict. For example:
?- write(t{a:x}.get(a)).
x
?- write(t{a:x}.get(b)).
false.
?- write(t{a:t{b:x}}.get(a/b)).
x
- put(+New)
- Evaluates to a new dict where the key-values in New replace
or extend the key-values in the original dict. See put_dict/3.
- get(?KeyPath,
+Default)
- Same as get/1 , but if no match is found the function evaluates to Default.
If KeyPath contains variables possible choice points are
respected and the function only evaluates to Default if the
pattern has no matches.
- put(+KeyPath,
+Value)
- Evaluates to a new dict where the KeyPath-Value
replaces or extends the key-values in the original dict. KeyPath
is either a key or a term KeyPath/Key,182Note
that we do not use the’.’functor here, because the
.
/2
would evaluate. replacing the value associated
with Key in a sub-dict of the dict on which the function
operates. See put_dict/4.
Below are some examples:
?- A = _{}.put(a, 1).
A = _G7359{a:1}.
?- A = _{a:1}.put(a, 2).
A = _G7377{a:2}.
?- A = _{a:1}.put(b/c, 2).
A = _G1395{a:1, b:_G1584{c:2}}.
?- A = _{a:_{b:1}}.put(a/b, 2).
A = _G1429{a:_G1425{b:2}}.
?- A = _{a:1}.put(a/b, 2).
A = _G1395{a:_G1578{b:2}}.