Пролог конвертировать минуты в часы - PullRequest
0 голосов
/ 14 февраля 2019

Это код, который я создал.

mins_to_hours(In, H, M):-
  In < 60,
  H = 0,
  M is In.
mins_to_hours(In, H, M):-
  In >= 60,
  H is H1+1,
  In1 is In-60,
  mins_to_hours(In1, H1, M).

Он отлично работает, когда минуты меньше 60, например

?- mins_to_hours(20,H,M).
H = 0,
M = 20 ;
false.

Однако при попытке запустить его более чем60 минут

?- mins_to_hours(80,H,M).

выводит исключение

ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR:    [9] _3198 is _3204+1
ERROR:    [8] mins_to_hours(80,_3232,_3234) at c:/.../xyz.pl:11
ERROR:    [7] <user>

в позиции H is H1+1,.

Есть идеи как это исправить?

Ответы [ 3 ]

0 голосов
/ 14 февраля 2019

Другая версия, которая может быть интересна, может быть такой, которая использует clpfd:

:- use_module(library(clpfd)).

min_hours(TotalMinutes, Hours, Minutes) :- 
    [TotalMinutes, Hours] ins 0..sup, 
    Minutes in 0..59, 
    TotalMinutes #= Hours*60 + Minutes.

Преимущество этого метода в том, что он работает с различными экземплярами:

?- min_hours(600, Hours, Minutes).
Hours = 10,
Minutes = 0.

?- min_hours(TotalHours, 10, 30).
TotalHours = 630.
0 голосов
/ 19 февраля 2019

Так много кода, что у меня кружится голова.

Для SWI-пролога:

mins_to_hours(Min, H, M) :-
    divmod(Min, 60, H, M).

Для любого пролога:

mins_to_hours(Min, H, M) :-
    H is Min div 60,
    M is Min mod 60.
0 голосов
/ 14 февраля 2019

Вот исправленная версия вашего кода.

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).

Основные изменения:

  1. Чтобы избежать сообщения об ошибке (аргументы не достаточно созданы), так как ваш кодявляется рекурсивным, ему нужны отдельные входящие и исходящие переменные, т.е. H0 с H1 и M0 с M1.
  2. Чтобы иметь возможность использовать дополнительные переменные, необходимые при добавлении предиката-помощника, т.е. mins_to_hours_helper.
  3. Минуты в и начальная минутная переменные в предикате помощника фактически одинаковы.
  4. В рекурсивном коде создаются точки выбора, но ожидается, что ответ будет детерминированным.Это решается с помощью сокращения (!) В базовом случае.

Вот несколько тестовых случаев (использует 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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...