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
terms in its arguments into a conjunction of calls to ./3
defined in the
./2system 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 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.
./2
./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 len181as 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:
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
./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}}.