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

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

问题描述

这是我创建的代码.

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

当分钟数小于 60 时它工作正常,例如

?- mins_to_hours(20,H,M).H = 0,米 = 20 ;错误的.

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

?- mins_to_hours(80,H,M).

输出异常

错误:参数未充分实例化错误:在:错误:[9] _3198 是 _3204+1错误:[8] mins_to_hours(80,_3232,_3234) 在 c:/.../xyz.pl:11错误:[7] <用户>

在位置H是H1+1,.

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

解决方案

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

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 是 H0+1,M1为M0-60,mins_to_hours_helper(H1, M1, H, M).

主要变化是:

  1. 为了避免错误消息(参数未充分实例化),因为您的代码是递归的,它需要单独的传入和传出变量,即 H0H1M0M1.
  2. 为了能够使用附加变量,必须添加辅助谓词,即 mins_to_hours_helper.
  3. 在辅助谓词中,分钟和起始分钟变量实际上是相同的.
  4. 递归代码会创建选择点,但预期答案是确定性的.这是在基本情况下通过切割 (!) 解决的.

以下是一些测试用例(使用 SWI-Prolog):

:- begin_tests(mins_to_hours).测试(-1):-mins_to_hours(-1,H,M),断言(H == 0),断言(M == -1).测试(0):-mins_to_hours(0,H,M),断言(H == 0),断言(M == 0).测试(1):-mins_to_hours(1,H,M),断言(H == 0),断言(M == 1).测试(59):-mins_to_hours(59,H,M),断言(H == 0),断言(M == 59).测试(60):-mins_to_hours(60,H,M),断言(H == 1),断言(M == 0).测试(600):-mins_to_hours(600,H,M),断言(H == 10),断言(M == 0).测试(601):-mins_to_hours(601,H,M),断言(H == 10),断言(M == 1).:- end_tests(mins_to_hours).

运行测试用例:

?- run_tests.% PL-Unit: mins_to_hours ....... 完成% 7 项测试全部通过真的.

<小时>

注意:run_tests. 不适用于 SWISH

没有权限调用沙盒`'$current_module'(_4002,_4004)'

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

参见:sandbox.pl><小时>

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

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

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

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

<小时>

注意.

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

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

<小时>

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

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

原答案代码写成

声明:mins_to_hours(++Minutes_in:int, -H:int, -M:int) 已确定.

意思是

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

然而作为@false 注释

?- mins_to_hours(Total, H, 1), Total = 61, H = 1.错误的.声明:mins_to_hours(-Minutes_in:int, -H:int, +M:int) 是 det.?- Total = 61, H = 1, mins_to_hours(Total, H, 1).总计 = 61,H = 1.声明:mins_to_hours(+Minutes_in:int, +H:int, +M:int) 是det.

第一个示例返回false,(失败)但应该返回true,第二个示例为相同的值但在不同的模式下返回一个有效的答案.

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

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

因此,为了避免@false 的第一个示例返回实际上是错误的 false,它应该抛出 Arguments are not enough 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 是 H0+1,M1为M0-60,mins_to_hours_helper(H1, M1, H, M).

通过测试用例

?- run_tests.% PL-Unit: mins_to_hours ....... 完成% 7 项测试全部通过真的.

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

?- mins_to_hours(Total, H, 1), Total = 61, H = 1.错误:参数未充分实例化错误:在:错误:[11] _6584<60错误:[10] mins_to_hours_helper(0,_6612,_6614,1) 在 c:/XYZ.pl:23错误:[8] '<meta-call>'(user:(...,...)) <foreign>错误:[7] <用户>错误:错误:注意:由于最后调用优化,某些帧丢失.错误:在调试模式下重新运行您的程序 (:- debug.) 以获取更多详细信息.

This is the code I have created.

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

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

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

However when trying to run it for more than 60 minutes

?- mins_to_hours(80,H,M).

it outputs an exception

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>

at the position H is 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).

The major changes are:

  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.

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

To run the test cases:

?- run_tests.
% PL-Unit: mins_to_hours ....... done
% All 7 tests passed
true.


Note: run_tests. does not work with SWISH,

No permission to call sandboxed `'$current_module'(_4002,_4004)'

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

See: 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.

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


Note.

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.

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.


Update based on feedback from @false.

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

The original answer code was written as

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

meaning that

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

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.

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.

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.

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

delay unification after the cut

Here is the updated code:

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

which passes the test cases

?- 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天全站免登陆