- Какой самый короткий цикл вы могли бы иметь в своей базе данных фактов? Будет ли
circular(a, a).
цикл [a]
? Знание самого короткого цикла может помочь вам найти (одно из) условие (я) завершения для вашего предиката.
- Чтобы найти список, ваш предикат должен создать его. Ваш
in_cycle/2
никогда не упоминает никаких списков. Вам нужно использовать конструкцию [Head | Tail]
где-то там, чтобы иметь возможность добавлять элементы в список.
- Вы уже знаете кое-что о том, как выглядит ваш циклический список. Первый и последний элементы совпадают, и они совпадают с символом, для которого вы пытаетесь найти цикл. Используйте эту информацию.
- Чтобы узнать, когда вы завершили цикл, вам нужно запомнить, с какого символа вы начали. Чтобы быть в состоянии сделать это с помощью рекурсии, вам нужно сохранять состояние. Так что вам понадобится дополнительный предикат, где вы сохраняете это состояние. Например. что-то с предикатом типа
in_cycle(Current_symbol, Cycle, Start_symbol)
. Затем вы можете позвонить с вашего in_cycle/2
.
Давайте посмотрим на вашу попытку:
in_cycle(C, Cycle) :-
circular(C, Cycle1),
in_cycle(Cycle1, Cycle).
Вы можете использовать команду trace
в приглашении, чтобы увидеть, что происходит: trace, in_cycle(a, X).
Нажмите Пробел , чтобы пройтись по вашей программе. Нажмите h для получения справки и a для выхода. Используйте notrace.
, чтобы снова выйти из режима трассировки.
Пройдя через это, вы обнаружите, что ваш предикат прекрасно циклически проходит цикл, но ни в коем случае X
никогда не становится списком. Это плохо.
Давайте попробуем составить список. Как я упоминал в пункте (3), вы уже знаете кое-что о списке. Первый элемент списка совпадает с первым аргументом in_cycle
. Более того, элемент second в списке совпадает с элементом, который вы найдете в circular/2
. Итак, мы знаем, что цикл имеет как минимум два элемента. Как насчет этого?
in_cycle(First, [First, Next|Cycle]) :-
circular(First, Next),
in_cycle(Next, [Next|Cycle]).
Если вы проследите это сейчас, вы увидите, что с X
что-то происходит, но на самом деле ничего полезного нет. Cycle
остается загадкой, и мы просто бесконечно изучаем факты. Вам нужно какое-то конечное условие здесь. Давайте попробуем простой:
in_cycle(First, [First]).
in_cycle(First, [First, Next|Cycle]) :-
circular(First, Next),
in_cycle(Next, [Next|Cycle]).
Вау! in_cycle(a, X)
неожиданно дает результаты! Кажется, все возможные списки с использованием circular
соединений начинаются с a
. Это не совсем то, что мы хотим, но, может быть, мы приближаемся?
Одна проблема с этим заключается в том, что in_cycle(Next, [Next|Cycle])
на самом деле не правильно!
Если вы сделаете in_cycle(a, X)
, вы уже знаете, что X
должно стать [a, b, d, a]
, поэтому, заполнив эти значения в in_cycle(First, [First, Next|Cycle])
, вы получите:
First = a
Next = b
Cycle = [d, a]
Когда вы добираетесь до in_cycle(Next, [Next|Cycle])
, это означает, что это in_cycle(b, [b, d, a])
. Но [b, d, a]
это не цикл! Вы должны уметь как-то различать эти две ситуации. Один из способов сделать это - вызвать отдельный предикат, как я упоминал в (4), чтобы отследить, каким был ваш начальный элемент.