Почему Пролог падает в этом простом примере?

likes(tom,jerry).
likes(mary,john).
likes(mary,mary).
likes(tom,mouse).
likes(jerry,jerry).
likes(jerry,cheese).
likes(mary,fruit).
likes(john,book).
likes(mary,book).
likes(tom,john).

likes(john,X):-likes(X,john), X\=john.

Привет, выше приведен очень простой файл пролога с некоторыми фактами и одним правилом: Джон любит всех, кто любит его. Но после загрузки этого файла прологу и задают следующий запрос:

likes(john,X).

Программа вылетает. Причина в том, что пролог застревает на likes(john,john) хотя правило гласит, что X\=john,

Любой совет?

2 ответа

Решение

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

Это происходит из-за порядка выполнения, который использует пролог, он собирается перейти в бесконечную рекурсию в likes(X,john) в вашем правиле оно снова активирует правило - не факт - никогда не добираясь до X\=john немного.

Один из способов исправить это - назвать ваше правило иначе, чем ваш факт:

kindoflikes(tom,jerry).
kindoflikes(mary,john).
kindoflikes(mary,mary).
kindoflikes(tom,mouse).
kindoflikes(jerry,jerry).
kindoflikes(jerry,cheese).
kindoflikes(mary,fruit).
kindoflikes(john,book).
kindoflikes(mary,book).
kindoflikes(tom,john).

likes(Y,X):- kindoflikes(X,Y), X\=Y.
likex(Y,X):- kindoflikes(Y,X), X\=Y.

Обратите внимание на изменение X и Y в kindofliks в двух определениях правила. Итак, вы получите:

?- likes(john,X).
X = mary ;
X = tom ;
X = book.

Но вы не можете найти то, что нравится Джону, и вы можете сделать:

?- likes(jerry,X).
X = tom ;
X = cheese.

Ваш первый вопрос был, почему ваша программа падает. Я не уверен, какую систему Prolog вы используете, но многие системы выдают чистую "ошибку ресурса", которая может быть обработана изнутри Prolog.

Ваша настоящая проблема в том, что ваша программа не завершает работу для запроса likes(john, X), Он дает вам ожидаемые ответы, и только тогда он зацикливается.

? - любит (Джон, Х).
Х = книга;
Х = Мэри;
Х = том;
ОШИБКА: вне локального стека

Вам очень повезло, что вы обнаружили эту проблему так быстро. Представьте себе больше ответов, и не было бы так очевидно, что у вас хватит терпения пройти через все ответы. Но для этого есть ярлык. Спросите вместо этого:

? - любит (Джон, Х), ложь.

это false цель никогда не верна. Так что это с готовностью предотвращает любой ответ. В лучшем случае запрос с false в конце заканчивается. В настоящее время это не так. Причину такого прекращения лучше всего видно при рассмотрении следующего фрагмента ошибки (для получения дополнительной информации см. Другие ответы):

? - любит (Джон, Х), ложь.любит (том, Джерри): - ложь.любит (Мэри, Джон): - ложь.любит (мэри, мэри): - ложь.лайки (том, мышка): - ложь.любит (Джерри, Джерри): - ложь.любит (Джерри, сыр): - ложь.любит (мария, фрукт): - ложь.любит (Джон, книга): - ложь.любит (мэри, книга): - ложь.любит (Том, ​​Джон): - ложь.
любит (Джон,X):-
   любит (X, Джон), ложь,
   X \ = Джон

Так что именно эта маленькая часть вашей программы отвечает за переполнение стека. Чтобы решить проблему, мы должны сделать что-то в этой крошечной части. Вот один из них: добавить цель dif(X, john) такое, что правило теперь гласит:

любит (Джон,X):-
   диф (Х, Джон),
   любит (X, джон).

dif/2 доступно во многих системах Prolog, таких как: SICStus, SWI, YAP, B, IF.

Другие вопросы по тегам