Проблема с `\ +` в пролог-запросах с переменными - PullRequest
5 голосов
/ 12 мая 2011

Я читаю "Семь языков за семь недель", и я озадачен каким-то запросом Пролога, на который я не понимаю ответа "нет".

выглядит файл friends.plкак это:

likes(wallace, cheese).
likes(grommit, cheese).
likes(wendolene, sheep).

friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).

Я могу сделать несколько тривиальных запросов, например:

| ?- ['friends'].
compiling /home/marc/btlang-code/code/prolog/friends.pl for byte code...
/home/marc/btlang-code/code/prolog/friends.pl compiled, 12 lines read - 994 bytes written, 8 ms

yes
| ?- friend(wallace,grommit).

yes
| ?- friend(wallace,wendolene).

no

Это все, как и ожидалось.Теперь я хочу ввести переменную в запросе.Я хочу сказать, что Пролог предоставит мне список всех друзей Уоллеса.Я ожидаю X = grommit, но получаю no:

| ?- trace.
The debugger will first creep -- showing everything (trace)

yes
{trace}
| ?- friend(wallace,X).
      1    1  Call: friend(wallace,_16) ?
      2    2  Call: \+wallace=_16 ?
      3    3  Call: wallace=_16 ?
      3    3  Exit: wallace=wallace ?
      2    2  Fail: \+wallace=_16 ?
      1    1  Fail: friend(wallace,_16) ?

no
{trace}

Он даже не пытается объединить X (_16) с grommit.Зачем?

Ответы [ 4 ]

4 голосов
/ 12 мая 2011

Это определение друга:

friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).

Здесь важно то, что вы начинаете с \+(X = Y), который обычно определяется как:

\+ Goal :- Goal,!,fail

Обратите внимание, что это означаетчто если цель будет успешной, вы обязательно потерпите неудачу.Свободные переменные (которые не были назначены) всегда будут объединяться и, следовательно, будут равны, поэтому вы всегда будете терпеть неудачу со свободной переменной.Таким образом, он никогда не будет присваивать значение X или Y, если у него его еще нет.

Вместо этого

friend(X, Y) :-  likes(X, Z), likes(Y, Z), \+(X = Y)

будет вести себя больше, чем вы ожидаете.

Проблема здесь в том, что пролог дает вам мощные способы управления потоком программ, но они действительно не вписываются в его более логически ориентированный дизайн.Должна быть возможность выразить ограничения типа «отрицание как сбой» таким образом, чтобы эти проблемы не возникали.По этой причине я не большой поклонник пролога.

4 голосов
/ 12 мая 2011

Относительно комментария Филиппа JF выше:

Должна быть возможность выразить ограничения типа «отрицание как неудача» таким образом, что не производит эти проблемы.

Это возможно: современное решение таких проблем - это ограничения. В этом случае используйте, например, dif/2, доступный во всех серьезных системах Prolog.

3 голосов
/ 12 мая 2011

Первая подцель friend/2 равна \+(X = Y). Это выполняется сначала попыткой найти решение для X = Y, а затем отрицанием этого результата. Предикат =/2 примерно эквивалентен unify/2, то есть он пытается объединить левый операнд с правым операндом. Теперь, когда вы задаете запросы, используя, например, friend(wallace, gromit), два атома wallace и gromit не объединяются; но когда в переменную добавляется свободная переменная, она всегда объединяется с любым заданным термином, поэтому X = Y всегда успешен, поэтому \+(X = Y) всегда терпит неудачу, и выполнение никогда не проходит эту первую подцель.

1 голос
/ 05 июня 2011

Еще одна проблема, связанная с наличием ограничения неравенства, заключается в следующем: невозможно найти привязку для несвязанного X (исключая тривиальный случай его объединения с grommit на данный момент).Пролог находит привязки, пробегая свою базу данных, пытаясь объединить несвязанную переменную.Вот почему likes(grommit, Z) найдет некоторую привязку для Z, которая затем может быть обработана, поскольку в базе данных есть предложения likes.Но нет таких условий для неравенства grommit с чем-то, поэтому Prolog не может производить никаких привязок.В настоящее время предикат friend должен убедиться, что все переменные связаны, прежде чем можно будет проверить неравенство.

...