Итак, я пытаюсь написать предикат в прологе, который может взять список L1 и список L2 и вернуть список всех элементов в L1, которые не находятся в L2. Это то, что я до сих пор:Пролог: как избежать обратного хода без порезов?
% Append an element to a list.
myappendelem(X,L,[X|L]).
% True if input list contains X.
mycontains([H | T], X) :-
H == X;
mycontains(T,X).
% Does the work for notin().
nocontains([],_,A,A).
nocontains([H|T],L,A,R):-
mycontains(L,H),
nocontains(T,L,A,R);
myappendelem(H,A,AR),
nocontains(T,L,AR,R).
% Returns all elements in L1 not in L2.
notin(L1,L2,R):-
nocontains(L1,L2,[],X).
Это работает, однако она дает более одного ответа, например:
notin([5,1],[4,3,2,1],X).
X = [5];
X = [5,1].
Это является проблемой, так как я использую этот предикат, чтобы разобраться в пути в графе (L1 - список узлов, к которым я мог бы перейти, а L2 - это узлы, к которым я уже был), чтобы гарантировать, что я не буду посещать один и тот же узел более одного раза и застревать в цикле. Но эта реализация заставляет меня застревать в цикле, потому что она возвращается после того, как она пытается с первым X, и она терпит неудачу, к неизмененному X, попадая в бесконечный цикл между теми же двумя узлами, которые могут достигать друг друга. Я знаю, что это легко исправить, добавив отрубов nocontains следующим образом:
% Does the work for notin().
nocontains([],_,A,A).
nocontains([H|T],L,A,R):-
mycontains(L,H),!,
nocontains(T,L,A,R);
myappendelem(H,A,AR),!,
nocontains(T,L,AR,R).
Но есть способ достичь того же без сокращений? Поэтому, когда я использую notin, я получаю только один возможный ответ? (его для школы, и часть задания, чтобы не использовать какие-либо встроенные предикаты или оператор управления)
Edit:
Просто чтобы быть более конкретными ограничения задания: Это должно состоят из чистых фактов и правил, нам не разрешено использовать какие-либо встроенные предикаты или структуры управления (включая, но не ограничиваясь, арифметику, порезы или отрицание как отказ). Точка с запятой в порядке. Любые предикаты полезности, необходимые нам, нужно определить сами.
Спасибо за все ответы, но я начинаю думать, что это может быть больше проблемой с методом, который я использую для поиска пути между двумя узлами в графе, поскольку из ответов он не выглядит так: легкий путь вокруг этого.
Даже точка с запятой является оператором управления. Укажите, какие из них разрешены. – CapelliC
Сообщите своим инструкторам, чтобы они научили Prolog множеством предикатов, которые фактически позволяют решать задачи, которые они задают. Чтобы выразить, что два члена отличаются * чисто реляционным способом *, используйте 'dif/2'. В частности, использование 'dif/2' позволяет вам выразить то, что вам нужно: элемент, который * не * встречается в списке. Это * не * требует арифметических, управляющих структур (кроме '(,)/2'), сокращений или отрицаний как отказ. – mat