Predicates with =.. operator in Prolog - prolog

Last time I learnt about =.. that can translate a list to term and opposite.
I have 3 predicates to do, first one is the one that translates a list to a term. I came up with sth like this:
list_to_term(List, Functor, Term) :-
Term =.. [Functor | List].
Is it okey? Enough? Or I miss something?
The other predicate is count(A,T,N) for element A, in term T with number N that is true if N is a count of elements A in term T... Can anyone help me with this one or how to start?
?- count(a,f(a),N).
N = 1
?- count(a,f(a,g(b,a),N).
N = 2.
?- count(a,f(a,g(X,a),N).
N = 2.

Looking at the answer of this post you can reuse the predicate flatten_term/2, a little bit modified to handle free variables, to sove your problem. Here is the code for a basic solution:
flatten_term(Term,[Term]):-
(atomic(Term);var(Term)),!.
flatten_term(Term,Flat):-
Term =.. TermList,
flatten_term_list(TermList,Flat),!.
flatten_term_list([],[]):-!.
flatten_term_list([H|T],List):-
flatten_term(H,HList),
flatten_term_list(T,TList),
append(HList,TList,List),!.
occurrences(_,[],N,N):-!.
occurrences(A,[H|T],N,Tot):-
A \== H,!,
occurrences(A,T,N,Tot).
occurrences(A,[H|T],N,Tot):-
A == H,!,
N1 is N+1,
occurrences(A,T,N1,Tot).
count(A,Term,N):-
flatten_term(Term,Flatten),
occurrences(A,Flatten,0,N).
?- count(a,f(a,g(X,a),d),T).
T = 2.
?- count(X,f(a,g(X,a),d),T).
T = 1
First of all you flatten the term using flatten_term/2. Then simply count the occurrences of the element you want to find using occurrences/4. You can, if you want, modify flatten_term/2 to avoid the usage of occurrences/4 and so scan the term (list) only one time... Something like: flatten_term(Term,Flatten,ElementToFind,Counter,Total).

Start by solving a more general problem of counting the terms in a list. Processing a term is processing a singleton list containing that term, after all:
count(A,T,N):- count(A, [T|Z],Z, 0,N).
count(_, [], [], C,N):- N is C, !.
count(A, [T|B],Z, C,N):- ?=(A,T), A=T, !, count(A, B,Z, C+1,N).
count(A, [T|B],Z, C,N):- ?=(A,T), T=..[_|S], !, append(S,Y,Z), count(A, B,Y, C,N).
count(A, [_|B],Z, C,N):- count(A, B,Z, C,N).
This opens up each head term in a list in succession and appends its argument terms to that list thus using it as a queue... thus processing the predicate's second argument T in a breadth-first manner.
This assumes A argument is an atom, and ?= is used to avoid instantiating the free variables we might encounter, and instead to skip over them, as your examples seem to indicate.

Is it okey? Enough? Or I miss something?
Prolog's =../2 predicate [swi-doc] can "pack" and "unpack" a list that contains the functor name and its arguments in a term and vice versa. So one can use this to construct a term, or to analyze a term. For example:
?- f(a,g(b,a)) =.. L.
L = [f, a, g(b, a)].
Here f is the functor name, and a and g(b, a) are the arguments. These arguments can be terms as well, and then we thus need to unpack these arguments further.
We can for example obtain all the subterms of a term with:
subterms(T, T) :-
\+ var(T).
subterms(T, ST) :-
\+ var(T),
T =.. [_|As],
member(A, As),
subterms(A, ST).
For example:
?- subterms(f(a,g(X,a)),N).
N = f(a, g(X, a)) ;
N = a ;
N = g(X, a) ;
N = a ;
false.
Now that we obtained all (sub)terms, we can slightly rewrite the predicate to count the number of elements that match:
subterm_query(Q, T) :-
Q == T.
subterm_query(Q, T) :-
\+ var(T),
T =.. [_|As],
member(A, As),
subterm_query(Q, A).
so we obtain if we query for a:
?- subterm_query(a, f(a,g(X,a))).
true ;
true ;
false.
If we can use the aggregate library, we can make use of the aggregate_all/3 predicate to count the number of times, the predicate was succesful:
?- aggregate_all(count, subterm_query(a, f(a,g(X,a))), Count).
Count = 2.
If not, you need to implement a mechanism that returns 1 for a match, and sums up recursively the matches of the child terms. I leave this as an exercise.

Related

How to improve this code that looks for a specific number in a list?

I'm writing prolog code that finds a certain number; a number is the right number if it's between 0 and 9 and not present in a given list. To do this I wrote a predicate number/3 that has the possible numbers as the first argument, the list in which the Rightnumber cannot be present and the mystery RightNumber as third argument:
number([XH|XT], [H|T], RightNumber):-
member(XH, [H|T]), !,
number(XT, [H|T], RightNumber).
number([XH|_], [H|T], XH):-
\+ member(XH, [H|T]).
so this code basically says that if the Head of the possible numbers list is already a member of the second list, to cut of the head and continue in recursion with the tail.
If the element is not present in the second list, the second clause triggers and tells prolog that that number is the RightNumber. It's okay that it only gives the first number that is possible, that's how I want to use it.
This code works in theory, but I was wondering if there's a better way to write it down? I'm using this predicate in another predicate later on in my code and it doesn't work as part of that. I think it's only reading the first clause, not the second and fails as a result.
Does anybody have an idea that might improve my code?
sample queries:
?- number([0,1,2,3,4,5,6,7,8,9], [1,2], X).
X = 3
?- number([0,1,2,3,4,5,6,7,8,9], [1,2,3,4,5,6,7,8,0], X).
X = 9
First, the code does not work. Consider:
?- number(Xs, Ys, N).
nontermination
This is obviously bad: For this so-called most general query, we expect to obtain answers, but Prolog does not give us any answer with this program!
So, I first suggest you eliminate all impurities from your program, and focus on a clean declarative description of what you want.
I give you a start:
good_number(N, Ls) :-
N in 0..9,
maplist(#\=(N), Ls).
This states that the relation is true if N is between 0 and 9, and N is different from any integer in Ls. See clpfd for more information about CLP(FD) constraints.
Importantly, this works in all directions. For example:
?- good_number(4, [1,2,3]).
true.
?- good_number(11, [1,2,3]).
false.
?- good_number(N, [1,2,3]).
N in 0\/4..9.
And also in the most general case:
?- good_number(N, Ls).
Ls = [],
N in 0..9 ;
Ls = [_2540],
N in 0..9,
N#\=_2540 ;
Ls = [_2750, _2756],
N in 0..9,
N#\=_2756,
N#\=_2750 .
This, with only two lines of code, we have implemented a very general relation.
Also see logical-purity for more information.
First of all, your predicate does not work, nor does it check all the required constraints (between 0 and 9 for instance).
Several things:
you unpack the second list [H|T], but you re-pack it when you call member(XH, [H|T]); instead you can use a list L (this however slightly alters the semantics of the predicate, but is more accurate towards the description);
you check twice member/2ship;
you do not check whether the value is a number between 0 and 9 (and an integer anyway).
A better approach is to construct a simple clause:
number(Ns, L, Number) :-
member(Number, Ns),
integer(Number),
0 =< Number,
Number =< 9,
\+ member(Number, L).
A problem that remains is that Number can be a variable. In that case integer(Number) will fail. In logic we would however expect that Prolog unifies it with a number. We can achieve this by using the between/3 predicate:
number(Ns, L, Number) :-
member(Number, Ns),
between(0, 9, Number),
\+ member(Number, L).
We can also use the Constraint Logic Programming over Finite Domains library and use the in/2 predicate:
:- use_module(library(clpfd)).
number(Ns, L, Number) :-
member(Number, Ns),
Number in 0..9,
\+ member(Number, L).
There are still other things that can go wrong. For instance we check non-membership with \+ member(Number, L). but in case L is not grounded, this will fail, instead of suggesting lists where none of the elements is equal to Number, we can use the meta-predicate maplist to construct lists and then call a predicate over every element. The predicate we want to call over every element is that that element is not equal to Number, so we can use:
:- use_module(library(clpfd)).
number(Ns, L, Number) :-
member(Number, Ns),
Number in 0..9,
maplist(#\=(Number), L).

Prolog - count occurrence of number

I want to write predicate which can count all encountered number:
count(1, [1,0,0,1,0], X).
X = 2.
I tried to write it like:
count(_, [], 0).
count(Num, [H|T], X) :- count(Num, T, X1), Num = H, X is X1 + 1.
Why doesn't work it?
Why doesn't work it?
Prolog is a programming language that often can answer such question directly. Look how I tried out your definition starting with your failing query:
?- count(1, [1,0,0,1,0], X).
false.
?- count(1, Xs, X).
Xs = [], X = 0
; Xs = [1], X = 1
; Xs = [1,1], X = 2
; Xs = [1,1,1], X = 3
; ... .
?- Xs = [_,_,_], count(1, Xs, X).
Xs = [1,1,1], X = 3.
So first I realized that the query does not work at all, then I generalized the query. I replaced the big list by a variable Xs and said: Prolog, fill in the blanks for me! And Prolog did this and reveals us precisely the cases when it will succeed.
In fact, it only succeeds with lists of 1s only. That is odd. Your definition is too restricted - it correctly counts the 1s in lists where there are only ones, but all other lists are rejected. #coder showed you how to extend your definition.
Here is another one using library(reif) for
SICStus|SWI. Alternatively, see tfilter/3.
count(X, Xs, N) :-
tfilter(=(X), Xs, Ys),
length(Ys, N).
A definition more in the style of the other definitions:
count(_, [], 0).
count(E, [X|Xs], N0) :-
if_(E = X, C = 1, C = 0),
count(E, Xs, N1),
N0 is N1+C.
And now for some more general uses:
How does a four element list look like that has 3 times a 1 in it?
?- length(L, 4), count(1, L, 3).
L = [1,1,1,_A], dif(1,_A)
; L = [1,1,_A,1], dif(1,_A)
; L = [1,_A,1,1], dif(1,_A)
; L = [_A,1,1,1], dif(1,_A)
; false.
So the remaining element must be something different from 1.
That's the fine generality Prolog offers us.
The problem is that as stated by #lurker if condition (or better unification) fails then the predicate will fail. You could make another clause for this purpose, using dif/2 which is pure and defined in the iso:
count(_, [], 0).
count(Num, [H|T], X) :- dif(Num,H), count(Num, T, X).
count(Num, [H|T], X) :- Num = H, count(Num, T, X1), X is X1 + 1.
The above is not the most efficient solution since it leaves many choice points but it is a quick and correct solution.
You simply let the predicate fail at the unification Num = X. Basically, it's like you don't accept terms which are different from the only one you are counting.
I propose to you this simple solution which uses tail recursion and scans the list in linear time. Despite the length, it's very efficient and elegant, it exploits declarative programming techniques and the backtracking of the Prolog engine.
count(C, L, R) :-
count(C, L, 0, R).
count(_, [], Acc, Acc).
count(C, [C|Xr], Acc, R) :-
IncAcc is Acc + 1,
count(C, Xr, IncAcc, R).
count(C, [X|Xr], Acc, R) :-
dif(X, C),
count(C, Xr, Acc, R).
count/3 is the launcher predicate. It takes the term to count, the list and gives to you the result value.
The first count/4 is the basic case of the recursion.
The second count/4 is executed when the head of the list is unified with the term you are looking for.
The third count/4 is reached upon backtracking: If the term doesn’t match, the unification fails, you won't need to increment the accumulator.
Acc allows you to scan the entire list propagating the partial result of the recursive processing. At the end you simply have to return it.
I solved it myself:
count(_, [], 0).
count(Num, [H|T], X) :- Num \= H, count(Num, T, X).
count(Num, [H|T], X) :- Num = H, count(Num, T, X1), X is X1 + 1.
I have decided to add my solution to the list here.
Other solutions here use either explicit unification/failure to unify, or libraries/other functions, but mine uses cuts and implicit unification instead. Note my solution is similar to Ilario's solution but simplifies this using cuts.
count(_, [], 0) :- !.
count(Value, [Value|Tail],Occurrences) :- !,
count(Value,Tail,TailOcc),
Occurrences is TailOcc+1.
count(Value, [_|Tail], Occurrences) :- count(Value,Tail,Occurrences).
How does this work? And how did you code it?
It is often useful to equate solving a problem like this to solving a proof by induction, with a base case, and then a inductive step which shows how to reduce the problem down.
Line 1 - base case
Line 1 (count(_, [], 0) :- !.) handles the "base case".
As we are working on a list, and have to look at each element, the simplest case is zero elements ([]). Therefore, we want a list with zero elements to have no instances of the Value we are looking for.
Note I have replaced Value in the final code with _ - this is because we do not care what value we are looking for if there are no values in the list anyway! Therefore, to avoid a singleton variable we negate it here.
I also added a ! (a cut) after this - as there is only one correct value for the number of occurrences we do not want Prolog to backtrack and fail - therefore we tell Prolog we found the correct value by adding this cut.
Lines 2/3 - inductive step
Lines 2 and 3 handle the "inductive step". This should handle if we have one or more elements in the list we are given. In Prolog we can only directly look at the head of the list, therefore let us look at one element at a time. Therefore, we have two cases - either the value at the head of the list is the Value we are looking for, or it is not.
Line 2
Line 2 (count(Value, [Value|Tail],Occurrences) :- !, count(Value,Tail,TailOcc), Occurrences is TailOcc+1.) handles if the head of our list and the value we are looking for match. Therefore, we simply use the same variable name so Prolog will unify them.
A cut is used as the first step in our solution (which makes each case mutually exclusive, and makes our solution last-call-optimised, by telling Prolog not to try any other rules).
Then, we find out how many instances of our term there are in the rest of the list (call it TailOcc). We don't know how many terms there are in the list we have at the moment, but we know it is one more than there are in the rest of the list (as we have a match).
Once we know how many instances there are in the rest of the list (call this Tail), we can take this value and add 1 to it, then return this as the last value in our count function (call this Occurences).
Line 3
Line 3 (count(Value, [_|Tail], Occurrences) :- count(Value,Tail,Occurrences).) handles if the head of our list and the value we are looking for do not match.
As we used a cut in line 2, this line will only be tried if line 2 fails (i.e. there is no match).
We simply take the number of instances in the rest of the list (the tail) and return this same value without editing it.

List indexes on a recursive program?

I've been searching for something that might help me with my problem all over the internet but I haven't been able to make any progress. I'm new to logic programming and English is not my first language so apologize for any mistake.
Basically I want to implement this prolog program: discord/3 which has arguments L1, L2 lists and P where P are the indexes of the lists where L1[P] != L2[P] (in Java). In case of different lengths, the not paired indexes just fail. Mode is (+,+,-) nondet.
I got down the basic case but I can't seem to wrap my head around on how to define P in the recursive call.
discord(_X,[],_Y) :-
fail.
discord([H1|T1],[H1|T2],Y) :-
???
discord(T1,T2,Z).
discord([_|T1],[_|T2],Y) :-
???
discord(T1,T2,Z).
The two clauses above are what I came up to but I have no idea on how to represent Y - and Z - so that the function actually remembers the length of the original list. I've been thinking about using nth/3 with eventually an assert but I'm not sure where to place them in the program.
I'm sure there has to be an easier solution although. Thanks in advance!
You can approach this in two ways. First, the more declarative way would be to enumerate the indexed elements of both lists with nth1/3 and use dif/2 to ensure that the two elements are different:
?- L1 = [a,b,c,d],
L2 = [x,b,y,d],
dif(X, Y),
nth1(P, L1, X),
nth1(P, L2, Y).
X = a, Y = x, P = 1 ;
X = c, Y = y, P = 3 ;
false.
You could also attempt to go through both list at the same time and keep a counter:
discord(L1, L2, P) :-
discord(L1, L2, 1, P).
discord([X|_], [Y|_], P, P) :-
dif(X, Y).
discord([_|Xs], [_|Ys], N, P) :-
succ(N, N1),
discord(Xs, Ys, N1, P).
Then, from the top level:
?- discord([a,b,c,d], [a,x,c,y], Ps).
Ps = 2 ;
Ps = 4 ;
false.

Why do I get duplicate results in my `length/2` implementation in prolog?

I'm working through exercises in Prolog. I've implemented a predicate similar to length/2 (called ue_length here) like this:
%%
% ue_length/2
%%
% not a list predicate
\+(T) :- call(T), !, fail.
\+(_).
% target case
ue_length(List, Length) :- \+(is_list(List)), !, fail.
ue_length(List, Length) :- ue_length(List, 0, Length).
% standard cases
ue_length([], Length, Length).
ue_length([X], Part, Length) :- ue_length([], [Part], Length).
ue_length([X| Rest], Part, Length) :- ue_length(Rest, [Part], Length).
The result is supposed to be a term rather than a number: 0 for [], [0] for a list of length one and [...[0]...] (n brackets) for a list of length n.
When I query Prolog (SWI-Prolog 6) with e.g. [1,2,3,4,5] I get the correct result twice.
?- ue_length([1,2,3,4,5], X).
X = [[[[[0]]]]]
X = [[[[[0]]]]].
I'm new to Prolog. Can someone explain why I get a redundant result?
Minimize the problematic query
As a first step, reduce the size of your query. The same problem (redundant solutions) can be observed already with ue_length([1], X). alone.
But there is something else which is much more problematic:
Is your definition a relation?
?- ue_length(L,N).
false.
So your definition succeeds with a list [1] but fails with a variable in its place? This does not make any sense at all! Even looping would be a better behavior.
Another problematic case is
?- ue_length(L,0).
false.
Here, your definition should give L = [] as answer.
The culprit for this is the test using is_list/1. Simply drop the rule
ue_length(List, Length) :- \+(is_list(List)), !, fail. % incorrect!
Now your definition can also be used to ask the most general query which contains distinct variables in the arguments.
?- ue_length(L,N).
L = [], N = 0
; L = [_A], N = [0]
; L = [_A], N = [0]
; L = [_A, _B], N = [[0]]
...
This is one of the very nice properties of Prolog: You do not need to type in concrete data for your test cases. Just enter the most general query like a pro, and Prolog will do the rest for you.
Localize with false
To localize this redundancy, first think of how that could have happened. One simple possibility is that some clause in your program is redundant and can thus be deleted.
Let's say it's the last one. So I will insert a goal false into the last clause. And I try again the most general query. Alas ...
ue_length(List, Length) :- ue_length(List, 0, Length).
% standard cases
ue_length([], Length, Length).
ue_length([_X], Part, Length) :-
ue_length([], [Part], Length).
ue_length([_X| Rest], Part, Length) :-
false,
ue_length(Rest, [Part], Length).
?- ue_length(L,N).
L = [], N = 0
; L = [_A], N = [0]
; false.
That rule must be quite important, for now we get only answers for lists of length zero and one. So my guess was wrong. But my point is that you can see this very easily by simply using the most general query. The actual redundant clause is the other one. And don't forget to ask the most general query such that you can be sure you get all your answers!

Prolog - unusual cons syntax for lists

I have come across an unfamiliar bit of Prolog syntax in Lee Naish's paper Higher-order logic programming in Prolog. Here is the first code sample from the paper:
% insertion sort (simple version)
isort([], []).
isort(A.As, Bs) :-
isort(As, Bs1),
isort(A, Bs1, Bs).
% insert number into sorted list
insert(N, [], [N]).
insert(N, H.L, N.H.L) :-
N =< H.
insert(N, H.LO, H.L) :-
N > H,
insert(N, LO, L).
My confusion is with A.As in isort(A.As, Bs) :-. From the context, it appears to be an alternate cons syntax for lists, the equivalent of isort([A|As], Bs) :-.
As well N.H.L appears to be a more convenient way to say [N|[H|L]].
But SWI Prolog won't accept this unusual syntax (unless I'm doing something wrong).
Does anyone recognize it? is my hypothesis correct? Which Prolog interpreter accepts that as valid syntax?
The dot operator was used for lists in the very first Prolog system of 1972, written in Algol-W, sometimes called Prolog 0. It is inspired by similar notation in LISP systems. The following exemple is from the paper The birth of Prolog by Alain Colmerauer and Philippe Roussel – the very creators of Prolog.
+ELEMENT(*X, *X.*Y).
+ELEMENT(*X, *Y.*Z) -ELEMENT(*X, *Z).
At that time, [] used to be NIL.
The next Prolog version, written in Fortran by Battani & Meloni, used cases to distinguish atoms and variables. Then DECsystem 10 Prolog introduced the square bracket notation replacing nil and X.Xs with [] and [X,..Xs] which in later versions of DECsystem 10 received [X|Xs] as an alternative. In ISO Prolog, there is only [X|Xs], .(X,Xs), and as canonical syntax '.'(X,Xs).
Please note that the dot has many different rôles in ISO Prolog. It serves already as
end token when followed by a % or a layout character like SPACE, NEWLINE, TAB.
decimal point in a floating point number, like 3.14159
graphic token char forming graphic tokens as =..
So if you are now declaring . as an infix operator, you have to be very careful. Both with what you write and what Prolog systems will read. A single additional space can change the meaning of a term. Consider two lists of numbers in both notations:
[1,2.3,4]. [5].
1 .2.3.4.[]. 5.[].
Please note that you have to add a space after 1. In this context, an additional white space in front of a number may change the meaning of your terms. Like so:
[1|2.3]. [4]. 5. [].
1 .2.3. 4.[]. 5. [].
Here is another example which might be even more convincing:
[1,-2].
1.(-2).[].
Negative numbers require round brackets within dot-lists.
Today, there is only YAP and XSB left that still offer infix . by default – and they do it differently. And XSB does not even recognize above dot syntax: you need round brackets around some of the nonnegative numbers.
You wrote that N.H.L appears to be a more convenient way to say [N|[H|L]]. There is a simple rule-of-thumb to simplify such expressions in ISO Prolog: Whenever you see within a list the tokens | and [ immediately after each other, you can replace them by , (and remove the corresponding ] on the right side). So you can now write: [N,H|L] which does not look that bad.
You can use that rule also in the other direction. If we have a list [1,2,3,4,5] we can use | as a "razor blade" like so: [1,2,3|[4,5]].
Another remark, since you are reading Naish's paper: In the meantime, it is well understood that only call/N is needed! And ISO Prolog supports call/1, call/2 up to call/8.
Yes, you are right, the dot it's the list cons infix operator. It's actually required by ISO Prolog standard, but usually hidden. I found (and used) that syntax some time ago:
:- module(eog, []).
:- op(103, xfy, (.)).
% where $ARGS appears as argument, replace the call ($ARGS) with a VAR
% the calle goes before caller, binding the VAR (added as last ARG)
funcs(X, (V, Y)) :-
nonvar(X),
X =.. W.As,
% identify meta arguments
( predicate_property(X, meta_predicate M)
% explicitly exclude to handle test(dcg)
% I'd like to handle this case in general way...
, M \= phrase(2, ?, ?)
-> M =.. W.Ms
; true
),
seek_call(As, Ms, Bs, V),
Y =.. W.Bs.
% look for first $ usage
seek_call([], [], _Bs, _V) :-
!, fail.
seek_call(A.As, M.Ms, A.Bs, V) :-
M #>= 0, M #=< 9, % skip meta arguments
!, seek_call(As, Ms, Bs, V).
seek_call(A.As, _, B.As, V) :-
nonvar(A),
A = $(F),
F =.. Fp.FAs,
( current_arithmetic_function(F) % inline arith
-> V = (PH is F)
; append(FAs, [PH], FBs),
V =.. Fp.FBs
),
!, B = PH.
seek_call(A.As, _.Ms, B.As, V) :-
nonvar(A),
A =.. F.FAs,
seek_call(FAs, Ms, FBs, V),
!, B =.. F.FBs.
seek_call(A.As, _.Ms, A.Bs, V) :-
!, seek_call(As, Ms, Bs, V).
:- multifile user:goal_expansion/2.
user:goal_expansion(X, Y) :-
( X = (_ , _) ; X = (_ ; _) ; X = (_ -> _) )
-> !, fail % leave control flow unchanged (useless after the meta... handling?)
; funcs(X, Y).
/* end eog.pl */
I was advised against it. Effectively, the [A|B] syntax it's an evolution of the . operator, introduced for readability.
OT: what's that code?
the code above it's my attempt to sweeten Prolog with functions. Namely, introduces on request, by means of $, the temporary variables required (for instance) by arithmetic expressions
fact(N, F) :-
N > 1 -> F is N * $fact($(N - 1)) ; F is 1.
each $ introduce a variable. After expansion, we have a more traditional fact/2
?- listing(fact).
plunit_eog:fact(A, C) :-
( A>1
-> B is A+ -1,
fact(B, D),
C is A*D
; C is 1
).
Where we have many expressions, that could be useful...
This syntax comes from NU-Prolog. See here. It's probably just the normal list functor '.'/2 redefined as an infix operator, without the need for a trailing empty list:
?- L= .(a,.(b,[])).
L = [a,b]
Yes (0.00s cpu)
?- op(500, xfy, '.').
Yes (0.00s cpu)
?- L = a.b.[].
L = [a,b]
Yes (0.00s cpu)

Resources