查询将数字转换为数字失败

时间:2015-12-11 00:32:27

标签: prolog

split(0).
split(M,List) :-
    M > 0,
    MM is floor(M / 10),
    Z is M mod 10,
    append(List,[Z],SubList),
    nl,
    print(SubList),
    split(MM,SubList).

1 个答案:

答案 0 :(得分:2)

这可能是一个简单的错字:你的split/1事实有一个,而你的归纳案例有两个。修改您的第一行:

split(0,[]).

你应该以相反的方式使用append/3

append(SubList,[Z],List),

所以谓词就像:

split(0,[]).
split(M,List) :-
    M > 0,
    MM is floor(M / 10),
    Z is M mod 10,
    append(SubList,[Z],List),
    split(MM,SubList).

将解决问题部分:它将返回一个正确的答案。但随后陷入无限循环。原因是您在append/3List未实例化的情况下致电SubList,所以就像:

append(A,[3],B).

将其运行到运行时环境中会生成:

?- append(A,[3],B).
A = [],
B = [3] ;
A = [_G218718],
B = [_G218718, 3] ;
A = [_G218718, _G218724],
B = [_G218718, _G218724, 3] ;
A = [_G218718, _G218724, _G218730],
B = [_G218718, _G218724, _G218730, 3] ;
A = [_G218718, _G218724, _G218730, _G218736],
B = [_G218718, _G218724, _G218730, _G218736, 3] ;
A = [_G218718, _G218724, _G218730, _G218736, _G218742],
B = [_G218718, _G218724, _G218730, _G218736, _G218742, 3];

(等)

因此,append/3谓词成功的列表数量无限,所有这些列表都会失败,因为最终您使用split/2调用0需要一个空列表,并且事实并非如此。

累加器更优雅的解决方案

append/3与一个元素一起使用通常效率不高:每次插入会导致 O(n)时间复杂度,因此对于此问题,您的split/2谓词将会在O(n 2 )中运行。解决方案是使用累加器:通过递归调用更新的变量。在这种情况下,您的第一个谓词将split/2split/3相关联:带累加器的版本。

split(A,B) :-
    split(A,[],B).

现在split/3的归纳案例再次是A == 0的归纳案例。在这种情况下,我们将累加器视为最终结果:

split(0,B,B).

归纳案例意味着我们寻找数字,将其添加到累加器的头部,然后递归传递:

split(M,Acc,Res) :-
    M > 0,
    MM is floor(M / 10),
    Z is M mod 10,
    split(MM,[Z|Acc],Res).

所以把它们放在一起,我们的版本有以下代码:

split(A,B) :-
    split(A,[],B).

split(0,B,B).
split(M,Acc,Res) :-
    M > 0,
    MM is floor(M / 10),
    Z is M mod 10,
    split(MM,[Z|Acc],Res).