Прежде всего, как также отмечено в комментарии, всегда проверяйте одиночные предупреждения , а всегда исправляйте их, прежде чем пытаться что-либо еще. Системы Prolog выдают эти предупреждения не для развлечения! Они выдают их, потому что они часто указывают на серьезные ошибки в вашей программе. В этом конкретном случае, если я оставлю в ваших одиночных файлах, но в остальном применим свое исправление ниже, ваша программа будет вести себя следующим образом:
?- schedule([a-[1,2,3], b-[1,2,3], c-[1,2,3]], Schedule).
Schedule = [c-3, b-2, a-1] ;
Schedule = [c-2, b-3, a-1] ;
Schedule = [c-3, b-1, a-2] ;
Schedule = [c-1, b-3, a-2] ;
Schedule = [c-2, b-1, a-3] ;
Schedule = [c-1, b-2, a-3] ;
ERROR: Out of global stack
Теперь давайте рассмотрим проблему с возвратом. Помимо решения с a-1
вы также можете попробовать решения с a-2
и a-3
. Но в момент, когда вы рассматриваете термин времени клиента a-[1, 2, 3]
, у вас есть Customer = a
, Time = 1
, Times = [2, 3]
и TakenTimes = []
. 1
не является членом []
. Вы только когда-либо пробуете альтернативное время, если рассматриваемое в настоящее время Time
является членом TakenTimes
, но поскольку TakenTimes
является []
, и ничто не является его членом. Таким образом, вы никогда не будете пробовать альтернативное время для a
.
Проблема заключается в ручной рекурсии по доступному клиенту времени. Вы эффективно реализуете своего рода «оптимизацию», когда рассматриваете только одно решение, а не все возможные. Чтобы получить все возможные, вам необходимо перечислить (не повторять!) Все доступное время клиента. Примерно так:
schedule([], Schedule, Schedule).
schedule([Customer-AvailableTimes|CustomerTimes], PartialSchedule, Schedule):-
get_taken_times(PartialSchedule, TakenTimes),
member(Time, AvailableTimes),
\+ member(Time, TakenTimes),
schedule(CustomerTimes, [Customer-Time | PartialSchedule], Schedule).
Для данного списка TakenTimes
это пробует все разрешенные альтернативные времена для клиента. И, если вы исправите свои проблемы с синглтоном, это даст вам все решения, а затем красиво завершится:
?- schedule([a-[1,2,3], b-[1,2,3], c-[1,2,3]], Schedule).
Schedule = [c-3, b-2, a-1] ;
Schedule = [c-2, b-3, a-1] ;
Schedule = [c-3, b-1, a-2] ;
Schedule = [c-1, b-3, a-2] ;
Schedule = [c-2, b-1, a-3] ;
Schedule = [c-1, b-2, a-3] ;
false.
Еще одно примечание по вашей реализации get_taken_times/2
: это правда, что часто вам нужен аргумент аккумулятора для выполнения интересные вещи в списках. Но здесь это совсем не нужно, и ваше решение даже не такое общее, как могло бы быть:
?- get_taken_times(Xs, [1, 2, 3]).
Xs = [_2686-3, _2704-2, _2722-1] ;
ERROR: Out of global stack
Скорее, при связывании списков, где заголовки списков находятся в некотором отношении, мы обычно express это прямо в заголовке предложения. Примерно так:
get_taken_times([], []).
get_taken_times([_Customer-Time | CustomerTimes], [Time | Times]) :-
get_taken_times(CustomerTimes, Times).
Это ведет себя более логично:
?- get_taken_times(Xs, [1, 2, 3]).
Xs = [_2046-1, _2058-2, _2070-3].
Лучшим именем для этого предиката было бы что-то вроде pairs_seconds/2
или, возможно, pairs_values/2
. Он присутствует в библиотеке SWI-Prolog под последним именем.