这是您的代码的更正版本。
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
with H1
, and M0
with 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.
Note: run_tests.
不适用于SWISH,
No permission to call sandboxed `'$current_module'(_4002,_4004)'
因此您必须手动输入每个查询并手动检查结果。
See: 沙箱.pl
现在有一个更好的方法来做到这一点。
mins_to_hours(Minutes_in, H, M) :-
H is Minutes_in // 60,
M is Minutes_in rem 60.
请注意,这是确定性的,不是递归的,并且通过了所有测试用例。
See: f-///2(整数除法)和rem/2(整数除法的余数)
Note.
由于您没有指定当分钟数为负数时应该发生什么,但确实提供了将分钟数小于 60 并将其移至结果的代码,因此此代码会重现该响应。
代码的一个变体是使用mod/2而不是 rem/2。根据输入,这将给出不同的答案,但可能是期望的结果。
根据@false 的反馈进行更新。
当编写的代码超出了简单的练习时,需要使用modes心里。
原来的答案代码写为
声明: mins_to_hours(++Minutes_in:int, -H:int, -M:int) 是 det。
意思是
Minutes_in 必须绑定到一个整数
H 必须是一个变量
M 必须是一个变量
然而正如@false 所指出的
?- 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
,
第二个示例返回相同值但模式不同的有效答案。
虽然我的答案仅适用于一种模式answer作者:Daniel Lyons 与他人合作是因为它使用约束。
?- 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.