Prolog — Предикат не находит всех решений при отсутствии входных переменных

#prolog

#prolog

Вопрос:

Вот в чем моя проблема.

Мои факты и правила:

 fact1(green, red, blue).
fact1(purple, white, gray).

fact2(green, orange).
fact2(purple, cyan).

fact3(green, pink).
fact3(purple, black).

foo(A,B,C,D,E) :-
   fact1(A,B,C),
   fact2(A,D),
   fact3(A,E),
   write(A),
   write(B).
  

Теперь, если я спрошу SWI-Prolog foo(A,B,C,D,E). , результат будет

 ?- foo(A,B,C,D,E).
greenred
A = green, B = red, C = blue, D = orange, E = pink ;
purplewhite
A = purple, B = white, C = gray, D = cyan, E = black.
  

Моя цель состоит в том, чтобы пользователь видел только строки

 greenred
purplewhite
  

Для достижения этого я попытался изменить определение foo вот так:

 foo() :-
   fact1(A,B,C),
   fact2(A,D),
   fact3(A,E),
   write(A),
   write(B).
  

Но вывод этого предиката — это только:

 ?- foo().
greenred
true.
  

и не то, что я ожидал:

 ?- foo().
greenred
purplewhite
true.
  

Любая помощь приветствуется.

Комментарии:

1. Что вы имеете в виду «но, конечно, всегда выводит …»? Вы не сказали нам, как выглядят ваши факты, поэтому мы не знаем, каков ваш ожидаемый результат. У вас действительно есть несколько совпадающих фактов? Можете ли вы включить некоторые минимальные (фиктивные) данные, с помощью которых мы можем это воспроизвести? Я пробовал некоторые и не могу воспроизвести вашу проблему. Так что либо проблема в коде, который вы нам не показываете, либо я не понимаю, что вы имеете в виду. Как вы это запускаете? Что вы делаете, чтобы попытаться получить несколько совпадений?

2. спасибо за ваш ответ, я отредактировал свой вопрос с помощью некоторого фиктивного кода. Надеюсь, теперь вы понимаете, что я имею в виду.

3. Спасибо за обновление. О, у вас проблема с true выводом? Нажатие пробела по-прежнему выдает мне последующие совпадения даже при foo(). но он также печатает true после каждого совпадения, чего foo(A,B,C,D,E). не происходит?

4. Я протестировал это снова, и я действительно получаю только первое совпадение с foo (), затем true, а затем ничего. И да, как вы сказали, я также не получаю true между строками, что также является тем, что я хочу, если это возможно. Может быть, это swi-prolog? Или вы знаете другой способ, как я мог бы достичь желаемого результата?

5. Хорошо, итак, я протестировал свой код с помощью редактора swish only, и теперь я получаю тот же результат, что и @mercator. Интересно

Ответ №1:

Добавление fail/ 0 в конце настраивает это в цикл, управляемый сбоем, так что после получения ответа предикат завершается ошибкой и пробует другие точки выбора.

 foo :-
    fact1(A,B,_),
    fact2(A,_),
    fact3(A,_),
    write(A),
    write(B),
    nl,
    fail.
  

Пример запуска.

 ?- foo.
greenred
purplewhite
false.
  

Чтобы заставить Prolog вернуть true (на заднем плане злой голос говорит: «У нас есть способы заставить вас рассказать нам правду»), он должен быть успешным после сбоя, поэтому Prolog ищет другое предложение с именем foo . Добавив просто foo. в качестве второго предложения, Prolog теперь может найти это предложение и выполнить его. Поскольку он ничего не делает, он завершается успешно и возвращает true.

 foo.
  

Пример выполнения

 ?- foo.
greenred
purplewhite
true.
  

Полный исходный код

 foo :-
    fact1(A,B,_),
    fact2(A,_),
    fact3(A,_),
    write(A),
    write(B),
    nl,
    fail.
foo.
  

Комментарии:

1. Терминология: вы хотели сказать «предложение», а не «предикат». В «полном» коде у вас есть 1 предикат, который состоит из 2 предложений (1 правило и 1 факт).

2. Большое спасибо! Очень интересно, что SWISH обрабатывает это по-разному по сравнению с prolog. Это то, что я должен иметь в виду.

3. @repeat Спасибо. Изменено.