Prolog将分钟转换为小时 [英] Prolog convert mins to hours

查看:17
本文介绍了Prolog将分钟转换为小时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我创建的代码.

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 时,它可以正常工作,例如

It works fine when the minutes are less than 60, e.g.

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

但是当尝试运行超过 60 分钟时

However when trying to run it for more than 60 minutes

?- 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 的位置是 H1+1,.

任何想法如何解决这个问题?

Any ideas how to fix this?

推荐答案

这是您的代码的更正版本.

Here is the corrected version of your code.

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. 为避免错误消息(参数未充分实例化),因为您的代码是递归的,它需要单独的传入和传出变量,即 H0H1M0M1.
  2. 为了能够使用附加变量,必须添加辅助谓词,即 mins_to_hours_helper.
  3. 辅助谓词中的分钟数和起始分钟数变量实际上是相同的.
  4. 递归代码会创建选择点,但答案应该是确定性的.这可以通过在基本情况下的剪切 (!) 来解决.
  1. To avoid the error message (Arguments are not sufficiently instantiated) since your code is recursive it needs separate incoming and outgoing variables, i.e. H0 with H1, and M0 with M1.
  2. To be able to use the additional variables necessities adding a helper predicate, i.e. mins_to_hours_helper.
  3. The minutes in and the starting minutes variable are actually the same in the helper predicate.
  4. Being recursive the code creates choice-points, but the answer is expected to be deterministic. This is solved with a cut (!) in the base case.

这里有一些测试用例(使用 SWI-Prolog):

Here are some test cases (Uses 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)'

因此您必须手动输入每个查询并手动检查结果.

so you will have to enter each query manually and manually check the results.

参见:sandbox.pl

现在有一个更好的方法来做到这一点.

Now for a much better way to do this.

mins_to_hours(Minutes_in, H, M) :-
    H is Minutes_in // 60,
    M is Minutes_in rem 60.

请注意,这是确定性的,不是递归的,并且通过了所有测试用例.

Notice that this is deterministic, is not recursive, and passes all of the test cases.

参见:f-///2(整数除法)和 rem/2(整数除法的余数)

See: f-///2 (Integer division) and rem/2 (Remainder of integer division)

注意.

由于您没有指定当分钟数为负数时应该发生什么,但确实提供了将分钟数少于 60 分钟并将其移至结果的代码,因此此代码会重现该响应.

Since you did not specify what should happen when the minutes are negative but did provide code that takes the minutes less than 60 and moves them to the result, this code reproduces that response.

代码的一个变体是使用 mod/2 而不是 rem/2.这将根据输入给出不同的答案,但可能是所需的结果.

A variation on the code is to use mod/2 instead of rem/2. This will give a different answer depending upon the input, but might be the desired result.

根据@false 的反馈进行更新.

Update based on feedback from @false.

当编写代码超出简单练习时,它需要使用 modes 记住.

When code is written beyond simple exercises it needs to written with modes in mind.

原来的答案代码写成

声明:mins_to_hours(++Minutes_in:int, -H:int, -M:int) 是det.

Declaration: mins_to_hours(++Minutes_in:int, -H:int, -M:int) is det.

意思是

Minutes_in 必须绑定一个整数
H 必须是一个变量
M 必须是一个变量

Minutes_in has to be bound to an integer
H has to be a variable
M has to be a variable

然而正如@false 所指出的那样

however as @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,第二个示例返回相同值但模式不同的有效答案.

The first example returns false, (fails) but should have returned true, and the second example returns a valid answer for the same values but in a different mode.

虽然我的答案仅适用于一种模式,但 Daniel Lyons 的 answer 可以与其他人一起使用,因为它使用了约束.

While my answer only works in one mode the answer by Daniel Lyons works with others because it uses constraints.

?- mins_to_hours(Total, H, 1), Total = 61, H = 1.
Total = 61,
H = 1.

因此,为了避免@false 的第一个示例返回实际错误的 false,它应该抛出 Arguments are not enough instantiated 错误.@false 还指出最简单的方法是

So to avoid the first example by @false from returning false which is actually wrong, it should throw an Arguments are not sufficiently instantiated error. @false also notes the simplest way to do this is to

切割后延迟统一

这是更新后的代码:

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.

并给出第一个示例的错误:

and gives the ERROR for the first example:

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

这篇关于Prolog将分钟转换为小时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆