2016-04-24 2 views
7

Я перешел к Прологу после изучения логики высказываний и предикатов.Как читать предикаты в прологе

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

Я могу легко прочитать что-то вроде ниже. Так говорит

X является спуск из Y, если X является ребенком Y.

Затем он идет дальше сказать

X является спуск из Y, если X является дочерним Z и Z является спуск У.

descend(X,Y) :- 
    child(X,Y). 
descend(X,Y) :- 
    child(X,Z), 
    descend(Z,Y). 

Но однажды я попал в глядя в программировании списка. Я изо всех сил пытаюсь прочитать синтаксис предикатов. Например, ниже

remove([], _, []). 
remove([X | Xs], X, Ys) :- remove(Xs, X, Ys). 
remove([Y | Xs], X, [Y | Ys]) :- X \== Y, remove(Xs, X, Ys). 

От тестирования, он удаляет второй элемент, так, например, если я типа в

remove([a,b,c], b, Ys). 

Я хотел бы получить Ys = [a,c].

Но я не знаю, как прочитайте синтаксис, если кто-то может сломать его для меня, это было бы здорово.

ответ

2

Тот факт, что вам нужно проверить его, чтобы увидеть, что он делает, говорит, что remove/3, вероятно, не так хорошо назван. remove довольно общий и оставляет открытым вопрос «удалить что?». Кроме того, это императив, а Prolog хочет быть реляционный. Возможно, лучшим именем будет list_without/3, в котором говорится, что список в третьем аргументе является списком в первом аргументе, но без второго аргумента.

Как бы то ни было, давайте прочитаем, что у вас есть.

Чтение ваш remove/3 предикат может быть сделано следующим образом:

remove([], _, []). 

Пустой список еще пустой список, если удалить любой элемент.

remove([X | Xs], X, Ys) :- remove(Xs, X, Ys). 

Список Ys список [X|Xs] с X элементов удалены еслиYs списка я получаю после удаления всех элементов из XXs.

remove([Y | Xs], X, [Y | Ys]) :- X \== Y, remove(Xs, X, Ys). 

[Y|Ys] список [Y|Xs] с X элементов удалены еслиX не то же самое, как Y и Ys списка я получаю после удаления всех элементов из XXs.

Как упражнение, вы должны попробовать прочитать их снова, но используя более реляционное имя, например, переименованный пример.

+0

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

+0

@ user6248190 Начну с мысли о предикатной оговорке, говорящей: * Такое-то истинно **, если ** .... *, а затем последовательность условий. – lurker

+0

Извините еще одну вещь, есть ли более короткий способ сделать то, что делает предикат удаления? Почему есть 3 линии удаления? – user6248190

4

Поскольку у вас есть некоторый фон в логике, вам может показаться полезным прочитать правила как логические формулы. Давайте заменим (\ ==)/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). 
+2

Или сформулируйте это еще более кратко, используя 'tfilter/3' вместе с' dif/3': 'list_without_element (Es, Xs, E): - tfilter (dif (E), Es, Xs) .' – repeat

Смежные вопросы