Is there a simple way to use the symbol “.” as just an atom like “+”, “*”, “-”, etc

Is there a simple way to use the symbol “.” as just an atom like “+”, “*”, “-”, etc. As I don’t use dicts, I wish the symbol “.” to be open for other uses. The symbol “.” is so basic.

After very long time of history of Prolog in which “.” was bound binary operator for list notation, SWI-Prolog opened a new way for “.”, which was very impressive and something epoch making event. However, “.” it is now bound for only dicts, which disappointed me.

It would be nice for wider prolog users if there is a way to use the period symbol “.” as an usual symbol atom without putting term_expansion/2 nor goal_expansion/2.

From the docs for https://www.swi-prolog.org/pldoc/doc_for?object=op/3:

Precedence 0 removes the declaration.

You may be able to remove the operator by using 0 as the precedence, but of course this could affect other code.

Thank you for your advice. I will check it later soon.

I am going to resume my “open dict” project with some additional ideas inspired by recent topics on SSU, rbtree. I will try to use setarg for new version for efficiency. Anyway delayed evaluation of X.Y.Z… is still a key feature, so my request. Of course I know “.” is prolog reader’s matter, for example, parsing “full stop” convention and recognizing end of clauses, etc.

Removing the operator (by setting its precedence to 0) won’t change the term expansion that expands

p(X,Y) :- q(X.a, Y).

to

p(X, Y) :-
    '.'(X, a, C),
    q(C, Y).

This expansion is independent of operator definitions; it’ll produce the same result from

p(X, Y) :- q('.'(X,a), Y).
1 Like

Thanks! You’re right. Dicts are not using operators, but term expansion.

1 Like

EDIT
I just remember that my existing open dict library use the term_expansion trick
to convert X.Y to eliminate “.”. To be honest, at the same time I remember that I felt that I was doing something very ad hoc.
As it is in library(pac/open-dict.pl).

%  './2' and './3' are reserved for the dict in SWI-7.
%  './2' is untuchable for the user in a direct way.
period_term(X):- functor(X, (.), 2), !.
period_term(role(_,_)).

%
period_args(X, A, B):- X=..[(.), A, B].
period_args(role(A, B), A, B).

end of EDit

Even reading your comment, still I have to time to understand behavior of “.”.
I think as Prolog reader has a privilege to process “.”, it is impossible
for the prolog user to control “.” by defining term_expansion or goal_expansion. However, your sample shows that I am wrong. I am confused.

This log might shows how I am confused. I appreciate if anyone points
what I am missing.

% swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 8.5.3-33-gd89fac4a2)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- X = f(a.b).
EERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.

?- asserta(user:goal_expansion(A.B, '.'(A, B))..
|    .
ERROR: Syntax error: Operator expected
ERROR: asserta(user:goal_expansion(A.B, '.'(A, B)
ERROR: ** here **
ERROR: ).. . 

?- asserta(user:term_expansion(A.B, '.'(A, B))).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR:   [13] throw(error(instantiation_error,_8064))
ERROR:   [10] '<meta-call>'(user:user: ...) <foreign>

?- X = a.b.
ERROR: Type error: `dict' expected, found `a' (an atom)  % ' to get code highlight back in order
ERROR: In:
ERROR:   [13] throw(error(type_error(dict,a),_1908))
ERROR:   [10] '<meta-call>'(user:user: ...) <foreign>

?- current_op(X, Y, .).
X = 100,
Y = yfx.

?- write_canonical(a.b).
ERROR: Type error: `dict' expected, found `a' (an atom)  % ' to get code highlight back in order
ERROR: In:
ERROR:   [13] throw(error(type_error(dict,a),_9010))
ERROR:   [10] '<meta-call>'(user:user: ...) <foreign>
ERROR:    [9] toplevel_call(user:user: ...) at

?- write_canonical(X.b).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR:   [13] throw(error(instantiation_error,_1858))
ERROR:   [10] '<meta-call>'(user:user: ...) <foreign>
ERROR:    [9] toplevel_call(user:user: ...) at /Users/cantor/lib/swipl/boot/toplevel.pl:1117
ERROR: 
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.

?- current_op(X, Y, .).
X = 100,
Y = yfx.

As is, the last step of expand_goal/2 is to rewrite A.B arguments that appear in goals as calls to ./3 before the goal. Thus, p(A.B) becomes

 .(A,B,C),
 p(C).

The only way to avoid this is by making earlier steps in the rewrite process map the A.B term into something else.

If we want some way to have functional notation for dicts we need to reserve some syntax for it … It took a little while, but from what I see around it appears dicts have become quite popular among SWI-Prolog users.

As I have added EDIT to my reply to Peter.ludemannn, I already used the rewriting trick.

It would be possible that I thanks to SWI dict. So far no chance for me to use it.

Can you please provide an example for that? I am struggling to create *_expantion rules which can match / avoid / translate to sth else the dot notation.

In is simplest way:

:- use_module(library(terms)).

mapdot(In, Out) :-
	In =.. [.,A,B],
	Out = dot(A,B).

term_expansion(In, Out) :-
	mapsubterms(mapdot, In, Out).

hello(a.b) :-
	world(c.d).

Now, if we load this file and list hello/1 we get

?- listing(hello).
hello(dot(a, b)) :-
    world(dot(c, d)).

Not the In =.. [.,A,B] where we cannot write .(A,B) as that would evaluate …

2 Likes

If using modules you can redefine the ‘.’/3
if the module name is testmodule then

:- module( testmodule,[]).
:- redefine_system_predicate( testmodule:(.(_,_,_))).
.(Data, Func, Value):-  Value =.. ['.', Data,Func].

Now ‘.’ is a ‘.’/2

For example this works

?- testmodule:(A.B=one.two).
A = one,
B = two.
?- A.B=one.two.
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR:   [13] throw(error(instantiation_error,_6666))
ERROR:   [10] '<meta-call>'(user:user: ...) <foreign>
ERROR:    [9] toplevel_call(user:user: ...) at c:/program files/swipl/boot/toplevel.pl:1117
ERROR: 
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
?- 

Now you can use dicts and the redefined ‘.’ both

?- A = point{x:1, y:2} ,K=A.x, testmodule:( M.N=q.p.r).
A = point{x:1, y:2},
K = 1,
M = q.p,
N = r.

I like it, which is applicable to my pac macro expansion in a natural way. Thanks.

Also mapsubterm is a nice naming ! Also I have an expandable meta predicate mapargs (library(pac/expand-etc.pl)), which uses mutual recursive closures of pac to expand. My first impression the two are the same, I will check later. I am always willing to drop my macros which SWI-Prolog already supports.

I was not aware of redefine_system_predicate. Thanks. As my open_dict is unfiy-hook based, I am not sure for now that redefine_system_predicate is applicable for my purpose.

Probably not. redefine_system_predicate/1 was once added as it was not allowed to redefine any builtin predicate. Now you can redefine predicates in the user module as well as in normal modules, except for those that are part of the ISO standard (including some stuff that never managed to get official such as the core thread API). It is pretty unlikely that you want to redefine ISO predicates (I hope …)