Я предлагаю следующее решение, и я постараюсь esplain это
selNextDepH([], _, First, First).
selNextDepH([Hd | _], Now, _, Hd) :-
Now @<= Hd.
selNextDepH([Hd | Td], Now, First, NextDep) :-
Now @> Hd,
selNextDepH(Td, Now, First, NextDep).
selNextDep([Hd | Td], Now, NextDep) :-
selNextDepH([Hd | Td], Now, Hd, NextDep).
switchDep(dep(Day, Time), departure(Time, Day)).
nextDep(DayNow, TimeNow, NextDeparture) :-
findall(dep(Day, Time), departure(Time, Day), List),
sort(List, ListS),
selNextDep(ListS, dep(DayNow, TimeNow), NextDep),
switchDep(NextDep, NextDeparture).
Все начинают в nextDep/3
где findall/3
собрать все departure/2
но собирают они, как dep/2
, в обратном порядке (dep(Day, Time)
вместо departure(Time, Day)
), потому что это проще заказать
findall(dep(Day, Time), departure(Time, Day), List),
Далее мы сортируем список List
из dep/2
структур с sort/2
sort(List, ListS),
так в ListS
(отсортированный) мы имеем отклонения (в dep/2
форме) упорядочено день в качестве первого ключа и время, как второй.
Далее мы называем selNextDep/3
, чтобы найти следующий выезд в dep/2
форме (NextDep
)
selNextDep(ListS, dep(DayNow, TimeNow), NextDep),
и с switchDep/2
, мы получаем следующий вылет в departure/2
форме
switchDep(NextDep, NextDeparture).
swithcDep/2
тривиально, но selNextDep/3
нет (IMHO).
Идея, лежащая в основе selNextDep/3
, - это возврат (в третьем аргументе) первого элемента sel/2
элемента сортированного списка (первого аргумента), который больше, чем второй аргумент (время). Если не найден более крупный элемент, идея возвращает первый элемент списка (первый выход на следующей неделе).
Итак, я разработал простой selNextDep/3
, который вызывает только предложение хелпера (selNextDepH/4
) с теми же аргументами и добавляет первый элемент списка (в случае отказа при поиске большего элемента); что
selNextDep([Hd | Td], Now, NextDep) :-
selNextDepH([Hd | Td], Now, Hd, NextDep).
Для selNextDepH/4
терминал условие тривиально: если список пуст, вернуть (унифицировать с последним аргументом) первый элемент списка
selNextDepH([], _, First, First).
Если список не является пусто, то есть 2 случая: (1) теперь времени меньше (или равно), чем первый элемент списка, поэтому мы возвращаемся (унифицировать последний аргумент) первый элемент списка
selNextDepH([Hd | _], Now, _, Hd) :-
Now @<= Hd.
или (2) время теперь больше, чем первый аргумент списка, поэтому мы ищем более крупный отъезд в следующем списке
selNextDepH([Hd | Td], Now, First, NextDep) :-
Now @> Hd,
selNextDepH(Td, Now, First, NextDep).