Prolog将分钟转换为小时

时间:2019-02-14 10:30:37

标签: recursion 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,
M = 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,

有什么办法解决此问题吗?

3 个答案:

答案 0 :(得分:3)

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

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. 为避免错误消息(参数未充分实例化),因为您的代码是递归的,因此需要单独的传入和传出变量,即H0H1,以及M0和{{ 1}}。
  2. 为了能够使用附加变量的必要性,需要添加一个辅助谓词,即M1
  3. 分钟数和开始分钟数变量在辅助谓词中实际上是相同的。
  4. 代码是递归的,因此会创建选择点,但是答案应该是确定性的。这可以通过在基本情况下使用割号(!)来解决。

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

mins_to_hours_helper

要运行测试用例:

:- 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. SWISH不兼容,

run_tests.

所以您将不得不手动输入每个查询并手动检查结果。

请参阅:sandbox.pl


现在是一种更好的方法。

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

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

请参阅: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(Minutes_in, H, M) :-
    H is Minutes_in // 60,
    M is Minutes_in rem 60.

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

虽然我的回答仅在一种模式下有效,但Daniel Lyons的answer与其他模式兼容,因为它使用了约束。

true

因此,为了避免@false的第一个示例返回实际上是错误的?- mins_to_hours(Total, H, 1), Total = 61, H = 1. Total = 61, H = 1. ,它应该引发false错误。 @false还指出最简单的方法是

  

剪切后延迟统一

这是更新的代码:

Arguments are not sufficiently instantiated

通过测试用例

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.

答案 1 :(得分:3)

另一个有趣的版本可能是使用clpfd:

class DocumentDetailView(generic.DetailView):

  model = Document

  def get_context_data(self, object, **kwargs):
    context = super().get_context_data(object, **kwargs)
    context["doc_list"] = Document.objects.filter(document_title=object.document_title).order_by('revision_number')
    return context

其优点是可以与不同的实例一起使用:

:- use_module(library(clpfd)).

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

答案 2 :(得分:0)

太多的代码让我感到头晕。

对于SWI-Prolog:

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.