Как сделать Prolog способным генерировать все возможные решения для запроса

Я хотел бы иметь возможность генерировать все возможные списки элементов, с 'и' между двумя последними элементами (как в обычном языке). В любом списке не должно быть повторяющихся элементов. Итак, "три, два и четыре" - это правильный список, как и "два и один", или "пять, три, четыре, один и два". Я не ищу одноэлементные списки.

Я написал следующую программу. Когда я запрашиваю у Пролога конкретный список, он сообщит мне правильно, если это правильный список. Однако, когда я запрашиваю список (X), он генерирует списки только с двумя элементами.

Может ли кто-нибудь предложить способ заставить его генерировать все возможные списки, используя данные элементы? Спасибо!

У меня есть такие факты, как

element([one]).
element([two]).
element([three]).
element([four]), etc. etc.

Мои предикаты для создания списка L:

list(L):-
     element(E1),
     element(E2),
     E1 \= E2,
     append(E1, [and], X),
     append(X, E2, L).

%recursive case
list(L):-
     element(E),
     append(E, [','], X),
     append(X, Y, L),
     list(Y),
     not_in(E, Y).

not_in([X], [Y]):- X \= Y.
not_in([X], [H|T]):-
     [X] \= [H],
     not_in([X], T).

1 ответ

Зацикливание ошибка

Ваш код зацикливается, потому что list(L) определяется с точки зрения list(Y) (рекурсивное определение). element(E) выбирает первое вхождение, т.е. [one], а затем добавляет это в новый список Y, до бесконечности. Вы проверяете это E не повторяется в Y в последней строке, но цикл появляется перед этим.

list(L):-
  element(E),
  append(E, [','], X),
  append(X, Y, L),
  list(Y),
  not_in(E, Y).

Правильная реализация

С использованием append/3 несколько раз может запутаться, я использую DCG здесь. Хитрость заключается в том, чтобы держать список вокруг уже используемых элементов, чтобы мы могли заранее проверить наличие дубликатов. Это позволяет избежать зацикливания при попытке проверить это впоследствии.

list -->
  list([]).

list(T) -->
  element(T, H),
  [and],
  element([H|T], _).
list(T) -->
  element(T, H),
  [','],
  list([H|T]).

element(L, X) -->
  cardinal(X),
  {\+ memberchk(X, L)}.

cardinal(1) --> [one].
cardinal(2) --> [two].
cardinal(3) --> [three].
cardinal(4) --> [four].

Пример использования:

?- phrase(list, List).
List = [one, and, two] ;
...
List = [one, ',', two, ',', three, and, four] ;
...
List = [four, ',', three, ',', two, and, one] ;
false
Другие вопросы по тегам