Почему Пролог падает в этом простом примере?
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.