Вот исправленная версия вашего кода.
mins_to_hours(Minutes_in, H, M) :-
mins_to_hours_helper(0, Minutes_in, H, M).
mins_to_hours_helper(H0, M0, H0, M0):-
M0 < 60, !.
mins_to_hours_helper(H0, M0, H, M):-
M0 >= 60,
H1 is H0+1,
M1 is M0-60,
mins_to_hours_helper(H1, M1, H, M).
Основные изменения:
- Чтобы избежать сообщения об ошибке (аргументы не достаточно созданы), так как ваш кодявляется рекурсивным, ему нужны отдельные входящие и исходящие переменные, т.е.
H0
с H1
и M0
с M1
. - Чтобы иметь возможность использовать дополнительные переменные, необходимые при добавлении предиката-помощника, т.е.
mins_to_hours_helper
. - Минуты в и начальная минутная переменные в предикате помощника фактически одинаковы.
- В рекурсивном коде создаются точки выбора, но ожидается, что ответ будет детерминированным.Это решается с помощью сокращения (!) В базовом случае.
Вот несколько тестовых случаев (использует SWI-Prolog):
:- begin_tests(mins_to_hours).
test(-1) :-
mins_to_hours(-1,H,M),
assertion(H == 0),
assertion(M == -1).
test(0) :-
mins_to_hours(0,H,M),
assertion(H == 0),
assertion(M == 0).
test(1) :-
mins_to_hours(1,H,M),
assertion(H == 0),
assertion(M == 1).
test(59) :-
mins_to_hours(59,H,M),
assertion(H == 0),
assertion(M == 59).
test(60) :-
mins_to_hours(60,H,M),
assertion(H == 1),
assertion(M == 0).
test(600) :-
mins_to_hours(600,H,M),
assertion(H == 10),
assertion(M == 0).
test(601) :-
mins_to_hours(601,H,M),
assertion(H == 10),
assertion(M == 1).
:- end_tests(mins_to_hours).
Чтобы запустить тестовые случаи:
?- run_tests.
% PL-Unit: mins_to_hours ....... done
% All 7 tests passed
true.
Примечание: run_tests.
не работает с SWISH ,
No permission to call sandboxed `'$current_module'(_4002,_4004)'
, поэтому вам придется вводить каждый запрос вручную и проверять вручнуюрезультаты.
См .: sandbox.pl
Теперь гораздо лучший способ сделать это.
mins_to_hours(Minutes_in, H, M) :-
H is Minutes_in // 60,
M is Minutes_in rem 60.
Обратите внимание, чтоэто является детерминированным, не рекурсивным и проходит все тестовые случаи.
См .: f - /// 2 (целочисленное деление) и rem / 2 (Остаток целочисленного деления)
Примечание.
Поскольку вы не указали, что должно происходить, когда минуты отрицательные, но предоставили код, который занимает минуты меньше 60 и перемещает ихв результате этот код воспроизводит этот ответ.
Вариантом кода является использование mod / 2 вместо rem / 2.Это даст другой ответ в зависимости от ввода, но может быть желаемым результатом.
Обновление на основе обратной связи от @ false.
Когда код написан вне простых упражнений, он нуждаетсянаписано с учетом режимов .
Исходный код ответа был написан как
Объявление: mins_to_hours (++ Minutes_in: int, -H: int, -M:int) is det.
означает, что
Minutes_in должен быть связан с целым числом
H должен быть переменной
M должен быть переменной
однако как @false notes
?- mins_to_hours(Total, H, 1), Total = 61, H = 1.
false.
Declaration: mins_to_hours(-Minutes_in:int, -H:int, +M:int) is det.
?- Total = 61, H = 1, mins_to_hours(Total, H, 1).
Total = 61,
H = 1.
Declaration: mins_to_hours(+Minutes_in:int, +H:int, +M:int) is det.
Первый пример возвращает false
, (терпит неудачу), но должен был вернуть true
, а второй пример возвращает действительный ответ для тех же значений, но в другомРежим.
Хотя мой ответ работает только в одном режиме, ответ Даниэля Лайонса работает с другими, потому что он использует ограничения.
?- mins_to_hours(Total, H, 1), Total = 61, H = 1.
Total = 61,
H = 1.
Поэтому, чтобы избежать первого примера с помощью @false от возврата false
, что на самом деле неправильно, должно выдать ошибку Arguments are not sufficiently instantiated
.@false также отмечает, что самый простой способ сделать это -
задержка объединения после вырезания
Вот обновленный код:
mins_to_hours(Minutes_in, H, M) :-
mins_to_hours_helper(0, Minutes_in, H, M).
mins_to_hours_helper(H0, M0, H1, M1):-
M0 < 60, !,
H0 = H1,
M0 = M1.
mins_to_hours_helper(H0, M0, H, M):-
M0 >= 60,
H1 is H0+1,
M1 is M0-60,
mins_to_hours_helper(H1, M1, H, M).
который проходит тестовые случаи
?- run_tests.
% PL-Unit: mins_to_hours ....... done
% All 7 tests passed
true.
и выдает ОШИБКУ для первого примера:
?- mins_to_hours(Total, H, 1), Total = 61, H = 1.
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [11] _6584<60
ERROR: [10] mins_to_hours_helper(0,_6612,_6614,1) at c:/XYZ.pl:23
ERROR: [8] '<meta-call>'(user:(...,...)) <foreign>
ERROR: [7] <user>
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.