Прежде всего, =\=
- это неравенство значений арифметических выражений.Это не общий «неравный» предикат.Например, это не очень хорошо работает:
?- a =\= b.
ERROR: =\=/2: Arithmetic: `a/0' is not a function
Таким образом, у вашего предиката нет надежды работать на что-либо, кроме списка чисел или других арифметических выражений.Если ваша система Prolog имеет dif/2
, используйте это:
?- dif(a, b).
true.
Только если вышеприведенное не работает, используйте \=
для неравенства:
?- a \= b.
true.
(разница междуэти два факта в том, что dif
правильно обрабатывает переменные, а \=
нет.)
Теперь одна непосредственная проблема в вашем коде состоит в том, что вы сопоставляете список со списком как [H|T]
, а затем пытаетесь создатьновый список [_|H]
для рекурсивного вызова.Это поднимает красный флаг: если H
является заголовком первого списка, то в общем случае это не будет сам список.Но не-списки не должны отображаться как tail в конструкторе списка.Например, если мы сопоставим список [1, 2, 3]
:
?- [H|T] = [1, 2, 3].
H = 1,
T = [2, 3].
... и затем попытаемся создать новый список с этим H
в качестве хвоста:
?- [H|T] = [1, 2, 3], Xs = [42 | H].
H = 1,
T = [2, 3],
Xs = [42|1].
... результат не будет списком:
?- [H|T] = [1, 2, 3], Xs = [42 | H], is_list(Xs).
false.
Вы, вероятно, хотите иметь H
в качестве головы нового аккумулятора, например:
remove(X, [H|T], R0, R) :-
dif(X, H),
remove(X, T, [H|R0], R).
Еще одна вещь, которую я изменил из вашего второго предложения, - это то, что аккумулятор R0
не обязательно должен быть []
, как в вашем определении.По вашему определению, рекурсивный вызов немедленно завершится ошибкой, поскольку новый непустой аккумулятор не будет объединен с []
.
. В некоторых случаях это уже работает:
?- remove(a, [b, c, d], [], Result).
Result = [d, c, b] ;
false.
Но недля других:
?- remove(a, [a], [], Result).
false.
Пока у вас есть только два предложения: одно для пустого списка (который здесь не применяется) и другое для случая, когда удаляемый элемент не равен заголовкусписка (который здесь не относится!).Третий пункт необходим для случая, когда заголовком списка является удаляемый элемент:
remove(X, [X|T], R0, R) :-
... % fill in here
Редактировать: Как указано в комментариях, решениенабросок выше переворачивает список элементов в списке результатов.Это обычно для рекурсивных предикатов списка на основе аккумулятора: позже элементы списка становятся ранее элементами аккумулятора.
Однако, аккумулятор здесь не нужен.Результат может быть построен напрямую.Вот реализация:
remove(_X, [], []).
remove(X, [Y|Xs], [Y|Ys]) :-
dif(X, Y),
remove(X, Xs, Ys).
remove(X, [X|Xs], Ys) :-
remove(X, Xs, Ys).
Это работает как для положительных, так и для отрицательных тестовых случаев:
?- remove(a, [b, a, c], Result).
Result = [b, c] ;
false.
?- remove(a, [b, c, d], Result).
Result = [b, c, d] ;
false.
Это работает в общем случае:
?- remove(X, Xs, Ys).
Xs = Ys, Ys = [] ;
Xs = Ys, Ys = [_G4794505],
dif(X, _G4794505) ;
Xs = Ys, Ys = [_G4794601, _G4794604],
dif(X, _G4794604),
dif(X, _G4794601) ;
Xs = Ys, Ys = [_G4794697, _G4794700, _G4794703],
dif(X, _G4794703),
dif(X, _G4794700),
dif(X, _G4794697) ;
Xs = Ys, Ys = [_G4794793, _G4794796, _G4794799, _G4794802],
dif(X, _G4794802),
dif(X, _G4794799),
dif(X, _G4794796),
dif(X, _G4794793) ;
Xs = Ys, Ys = [_G4794889, _G4794892, _G4794895, _G4794898, _G4794901],
dif(X, _G4794901),
dif(X, _G4794898),
dif(X, _G4794895),
dif(X, _G4794892),
dif(X, _G4794889) ;
Xs = Ys, Ys = [_G4794985, _G4794988, _G4794991, _G4794994, _G4794997, _G4795000],
dif(X, _G4795000),
dif(X, _G4794997),
dif(X, _G4794994),
dif(X, _G4794991),
dif(X, _G4794988),
dif(X, _G4794985) .
Ноперечисленное выше не справедливо!Это только упражнение второе, а не третье.Мы можем получить справедливое перечисление, сгруппировав по длине Xs
:
?- length(Xs, N), remove(X, Xs, Ys).
Xs = Ys, Ys = [],
N = 0 ;
Xs = Ys, Ys = [_G4794582],
N = 1,
dif(X, _G4794582) ;
Xs = [X],
N = 1,
Ys = [] ;
Xs = Ys, Ys = [_G4794678, _G4794681],
N = 2,
dif(X, _G4794678),
dif(X, _G4794681) ;
Xs = [_G4794585, X],
N = 2,
Ys = [_G4794585],
dif(X, _G4794585) ;
Xs = [X, _G4794588],
N = 2,
Ys = [_G4794588],
dif(X, _G4794588) ;
Xs = [X, X],
N = 2,
Ys = [] ;
Xs = Ys, Ys = [_G4794774, _G4794777, _G4794780],
N = 3,
dif(X, _G4794774),
dif(X, _G4794780),
dif(X, _G4794777) .
Мы также можем использовать это «назад» ограниченным образом: оставив второй аргумент Xs
свободным и указав конкретныйсписок для третьего аргумента Ys
, мы получаем предикат , вставляющий данный элемент в Ys
во всех возможных местах, давая Xs
:
?- remove(a, Xs, [b, c, d]).
Xs = [b, c, d] ;
Xs = [b, c, d, a] ;
Xs = [b, c, d, a, a] ;
Xs = [b, c, d, a, a, a] .
Опять этонесправедливо, но опять же это можно исправить:
?- length(Xs, N), remove(a, Xs, [b, c, d]).
Xs = [b, c, d],
N = 3 ;
Xs = [b, c, d, a],
N = 4 ;
Xs = [b, c, a, d],
N = 4 ;
Xs = [b, a, c, d],
N = 4 ;
Xs = [a, b, c, d],
N = 4 ;
Xs = [b, c, d, a, a],
N = 5 . % etc.