Ошибка пролога без причины

Я создал следующий скрипт, однако он выдает мне ошибку, хотя с моей точки зрения он совершенно правильный. Что может быть причиной этого?

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]. 

Когда я запускаю это со следующим:

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

Это выдает мне следующую ошибку:

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

person truе    schedule 11.04.2014    source источник
comment
=\=/2 — это арифметический оператор, используемый для сравнения, если два арифметических выражения оцениваются как неравные. Вы используете его для не чисел. Попробуйте вместо этого использовать \== (термины не идентичны) или \= (термины не поддаются унификации).   -  person lurker    schedule 11.04.2014
comment
@lurker, почему бы не опубликовать свой ответ как ответ, чтобы вопрос можно было закрыть?   -  person Shon    schedule 11.04.2014


Ответы (1)


Указанная ошибка действительно имеет причину. :)

=\=/2 — это арифметический оператор, используемый для сравнения значения двух арифметических выражений на равенство, и он дает успех (истина), если они не равны. Это вызовет ошибку, если вы попытаетесь использовать его в нечисловых терминах.

Если вы хотите проверить, не идентичны ли термины, вы должны использовать \==. Например,

?- a \== b.
true.

?- X \== a.
true.

Если вы хотите проверить «не унифицируемый», вы должны использовать \=:

?- a \= b.
true.

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

Это само по себе заставит ваш предикат работать, хотя он находит решение более одного раза:

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

?-

Хотя в логике нет ошибки, сама по себе, есть небольшая подчистка, которую можно было бы сделать.

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].

Предложение remove_repeats([X,X], [X]). является избыточным, поскольку оно уже будет обработано remove_repeats([H,H|T], R) ..., за которым следует remove_repeats([X], [X]). Кроме того, пункт remove_repeats([X,Y], [X,Y]) :- X \= Y. также является избыточным, поскольку его будут обрабатывать remove_repeats([H1,H2|T], R) ... и remove_repeats([X], [X]).. Затем мы можем привести в порядок последнее предложение, включив объединение R в заголовок предложения:

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).

Избавление от избыточных правил также избавляет от избыточных результатов, поскольку у решения не будет более одного способа удовлетворить правила:

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

?-


ИЗМЕНИТЬ

Как указал @false в своем комментарии, если вы используете SWI Prolog, у вас есть dif/2 доступный вам предикат, который было бы неплохо использовать вместо =\=/2. Таким образом, указанное выше H1 \= H2 будет dif(H1, H2).

person lurker    schedule 11.04.2014
comment
Есть тег prolog-dif - person false; 15.04.2014