truе
truе

Reputation: 93

Prolog error for no reason

I have created following script, however, it throws me an error, even though from my point of view it is perfectly correct. What may be the cause to it?

remove_repeats([],[]).
remove_repeats([X],[X]).
remove_repeats([X,X],[X]).
remove_repeats([X,Y],[X,Y]):-X=\=Y.
remove_repeats([H,H|T],R):-remove_repeats([H|T],R).
remove_repeats([H1,H2|T],R):- H1=\=H2, remove_repeats([H2|T],Z), R=[H1|Z]. 

When I run this with following:

remove_repeats([a,b,b,c,c,c,c,c,d],Result).

It throws me following error:

ERROR: =\=/2 :Arithmetic: 'a=0' is not a function

Upvotes: 0

Views: 282

Answers (1)

lurker
lurker

Reputation: 58324

The error given does indeed have a reason. :)

=\=/2 is an arithmetic operator used for comparing the value of two arithmetic expressions for equality, and it yields success (true) if they're unequal. It will generate an error if you attempt to use it on non-numeric terms.

If you want to check if terms are not identical, you would use \==. For example,

?- a \== b.
true.

?- X \== a.
true.

If you want to check for "not unifiable" you would use \=:

?- a \= b.
true.

?- X \= a.   % X could be unified with 'a' to make them equal
false.

This by itself will make your predicate work, although it does find the solution more than once:

?- remove_repeats([a,b,b,c,c,c,c,c,d], Result).
Result = [a, b, c, d] ;
Result = [a, b, c, d] ;
false.

?-

Although there's not an error in the logic, per se, there is a bit of clean-up that could be done.

remove_repeats([], []).
remove_repeats([X], [X]).
remove_repeats([X,X], [X]).
remove_repeats([X,Y], [X,Y]) :- X \= Y.
remove_repeats([H,H|T], R) :- remove_repeats([H|T], R).
remove_repeats([H1,H2|T], R) :-
    H1 \= H2,
    remove_repeats([H2|T], Z),
    R = [H1|Z].

The clause remove_repeats([X,X], [X]). is redundant because it will already be handled by remove_repeats([H,H|T], R) ... followed by remove_repeats([X], [X]). Also, the clause remove_repeats([X,Y], [X,Y]) :- X \= Y. is also redundant because it will be handled by remove_repeats([H1,H2|T], R) ... and remove_repeats([X], [X]).. Then we can neaten up the last clause by including the unification of R into the head of the clause:

remove_repeats([], []).
remove_repeats([X], [X]).
remove_repeats([H,H|T], R) :- remove_repeats([H|T], R).
remove_repeats([H1,H2|T], [H1|Z]) :-
    H1 \= H2,
    remove_repeats([H2|T], Z).

Getting rid of the redundant rules also gets rid of the redundant results since the solution will not have more than one way to be satisfied by the rules:

?- remove_repeats([a,b,b,c,c,c,c,c,d], Result).
Result = [a, b, c, d] ;
false.

?-


EDIT

As @false pointed out in his comment, if you're using SWI Prolog, you have the dif/2 predicate available to you which would be good to use in place of =\=/2. So the above H1 \= H2 would be dif(H1, H2).

Upvotes: 1

Related Questions