Поскольку у вас есть некоторый фон в логике, вам может показаться полезным прочитать правила как логические формулы. Давайте заменим (\ ==)/2 по DIF/2 затем удалить/3 гласит:
remove([], _, [])
← true
remove([X | Xs], X, Ys)
← remove(Xs, X, Ys)
remove([Y | Xs], X, [Y | Ys])
← dif(X,Y)
∧ remove(Xs, X, Ys)
Обратите внимание, как стрелка импликации указывает на главу правила. Это означает, что тело правила является антецедентом, а глава правила является следствием. Итак, вы читаете правило как: если тело правила истинно, то глава правила является истинным. Цели в правилах связаны соединением. Обратите внимание, что факт имеет true
как антецедент, а это значит, что remove([], _, [])
всегда верно. С другой стороны, если тело правила ложно, это правило терпит неудачу, но предикат может все же сработать, если тело другого правила истинно. Если тела всех других правил также ложны, то предикат терпит неудачу. Таким образом, наличие нескольких правил для предиката является логическим или: предикат remove/3 преуспевает, если правило 1 ИЛИ правило2 ИЛИ правило3 успешно завершено.
Как вы специально просили указать синтаксис, также полезно ознакомиться с заголовком и хвостом для списков. То есть, вы можете написать первый элемент (ы) список явно затем конструктор списка |
и остальную часть списка:
[1|Xs]
... список начинается с 1
, а затем есть отдых
[1,2|Xs]
... список начинается с 1
и 2
сопровождаемого отдыха
[X|Xs]
... список имеет, по меньшей мере, один элемент, а затем отдыха
Обратите внимание, как элементы списка разделяются ,
, а остальная часть списка разделена |
. Термин после |
фактически является списком и может также быть пустым списком.Вот некоторые примеры равных списков:
[1]
такие же, как [1|[]]
[1,2]
= [1|[2]]
= [1|[2|[]]]
= [1,2|[]]
Для следующего списка есть уже 8 способов написать это:
[1,2,3]
= [1,2|[3]]
= [1|[2,3]]
= [1|[2|[3|[]]]]
= ...
С учетом приведенных выше замечаний вы затем изучали правила по одному за раз. Поскольку @lurker уже сделал это в своем ответе, я не буду вдаваться в подробности. Тем не менее, я хотел бы добавить, что если правило имеет несколько целей, как 3-й правило, в вашем примере, я считаю, что полезно пройти через цель один за один раз:
remove([Y | Xs], X, [Y | Ys]) :-
Элемента Y
из исходного списка также в списке без X
IF ...
remove([Y | Xs], X, [Y | Ys]) :-
dif(X,Y),
... X
отличается от Y
И ...
remove([Y | Xs], X, [Y | Ys]) :-
dif(X,Y),
remove(Xs, X, Ys).
... соотношение имеет место для Xs
, X
и Ys
.
Так почему же замена? Встроенный предикат (\ ==)/2 просто преуспевает или терпит неудачу без унификации или побочного эффекта. Это хорошо для тестирования неравенства сроков в данный момент времени, но не имеет никакого эффекта позже. Рассмотрим следующие запросы:
?- X=Y, X\==Y.
no
Первые переменные X
и Y
унифицированы, а затем тест на неравенство не выполняется. Но:
?- X\==Y, X=Y.
X = Y
Сначала тест на неравенство преуспевает, в противном случае Пролог даже не рассмотрит вторую цель. Затем X
и Y
успешно объединены. Это то, что я имею в виду под номером бездействия на. Итак, все, что я написал выше, при чтении предикатов не имеет смысла (\ ==)/2.
В короткую версию я бросить следующий в шляпе, используя if_/3 и =/3:
list_without_element([],[],_E).
list_without_element([X|Xs],L,E) :-
if_(X=E,L=Ys,L=[X|Ys]),
list_without_element(Xs,Ys,E).
совершенного спасибо, синтаксис был действительно путает меня и, кажется, так сильно отличаются от того, как я обычно читал предикаты. – user6248190
@ user6248190 Начну с мысли о предикатной оговорке, говорящей: * Такое-то истинно **, если ** .... *, а затем последовательность условий. – lurker
Извините еще одну вещь, есть ли более короткий способ сделать то, что делает предикат удаления? Почему есть 3 линии удаления? – user6248190