Creating a unique list of elements

Hi all,

I’m a bloody prolog-Newbie.

I’m using: SWI-Prolog version 9.04

I want the code to:

Deliver a list of unique combinations.

$ swipl test.pl

?- tst(A,  B).

A = berlin
B = frankfurt ;
A = frankfurt,
B = berlin ;

But what I’m getting is:

A list with duplicates.

$ swipl test.pl

?- tst(A,  B).

A = berlin,
B = frankfurt ;
A = berlin,
B = frankfurt ;
A = frankfurt,
B = berlin ;
A = frankfurt,
B = berlin ;
false.

My code looks like this:

city(berlin).
city(frankfurt).

unique([]).
unique([_]).
unique([H|T]) :-
    \+ contains(T, H),
    unique(T).

contains([], _) :- false.
contains([H|_], H).
contains([_|T], X) :- contains(T, X).

tst(A, B) :-
        city(A),
        city(B),
        unique([A,B]).

Thanks for any hints to learn, what I missed or failed to understand or explanations what is really going on here!

Can wrap in distinct/1

Example:

?- distinct(member(X, [a,b,c,b,a])).
X = a ;
X = b ;
X = c ;
false.

To break symmetry, can add a constraint using @>/2 of e.g.:

B @> A

If you look at your implementation of unique/1, you’ll see that both the second and third clause will succeed given a list with one item ( if T in clause 3 is []). That produces two answers for the same call (Prolog “or” is inclusive). You can see this if you try the query ?- city(A), unique([A]).

If this is undesirable, you have to ensure the third clause doesn’t succeed under these circumstances, e.g.,

unique([]).
unique([_]).
unique([H|T]) :-  T\=[],
    \+ contains(T, H),
    unique(T).

Alternatively you can use a cut ('!') in the second clause to “commit” to that choice, but if you’re just learning it’s probably best to avoid cuts for now.

2 Likes

@ridgeworks, your solutions works as expected. I’ll take my sweet time trying to follow your explanations. At the moment I’m quite lost.

I have also trouble finding the meaning of operators within the siwprolog documentation. Does anyone have a hint, where to look for operators and explanations of those? Regarding the official manual I found

https://www.swi-prolog.org/pldoc/man?section=operators

But there are only explanations of what type an operator is and how to create a new operator but nothing about the meaning of specific operators.

Thanks both of you for the answers!

Before going too much further, it might be worth a bit of your time learning how to use the debugger: SWI-Prolog -- Overview of the Debugger . Then you can preface any of your queries with trace and step through the execution.

Operators are pure syntactic sugar so their “meaning” is context sensitive. For example, see SWI-Prolog -- Arithmetic for the meaning of arithmetic operators when using the arithmetic predicates (is/2, =:=/2, etc.). But these same operators could be used to mean other things, just like JavaScript + can mean addition or string concatenation. And you can even define your own operators if you want to construct a domain specific language that the Prolog parser understands.

This might seem a little strange if you’re coming from a more conventional programming language, but it can be quite powerful. Just remember that X is Y+1 is actually parsed as (is(X,+(Y,1))) - see SWI-Prolog -- write_canonical/1 and try a few examples of your own.