Prolog无限循环问题

时间:2014-11-09 11:08:03

标签: prolog failure-slice

我有以下功能。 当我用final_filter([(2, 2)], R)调用它时,会打印很多" 2 2"对。当我评论get_all_sums(S, _)时,它可以正常工作,但是如果我单独测试get_all_sums(4, R)。我的工作也很好,可能是什么问题?

get_all_sums_R(NR, IT, []):- IT > NR - 2.
get_all_sums_R(NR, IT, R):-
    A is IT,
    B is NR-IT,
    A >= B,
    NEXT_IT is IT + 1,
    get_all_sums_R(NR, NEXT_IT, R_NEXT),
    append([(A, B)], R_NEXT, R).
get_all_sums_R(NR, IT, R):-
    A is IT,
    B is NR-IT,
    A < B,
    NEXT_IT is IT + 1,
    get_all_sums_R(NR, NEXT_IT, R).

get_all_sums(NR, R):-get_all_sums_R(NR, 2, R).


get_all_divisors(X, IT, []):-IT > X/2.
get_all_divisors(X, IT, R):-
    IT =< X/2,
    TMP_RES is mod(X, IT),
    TMP_RES =:= 0,
    NEXT_IT is IT + 1,
    get_all_divisors(X, NEXT_IT, R_NEXT),
    append([IT], R_NEXT, R).
get_all_divisors(X, IT, R):-
    IT =< X/2,
    NEXT_IT is IT + 1,
    get_all_divisors(X, NEXT_IT, R).

get_all_products_R([], _, []).
get_all_products_R([H|L], NR, R):-
    A is H,
    B is NR/H,
    A >= B,
    get_all_products_R(L, NR, NEXT_R),
    append([(A, B)], NEXT_R, R).
get_all_products_R([H|L], NR, R):-
    A is H,
    B is NR/H,
    A < B,
    get_all_products_R(L, NR, R).

get_all_products(NR, R):-
    get_all_divisors(NR, 2, R_LEFT),
    get_all_products_R(R_LEFT, NR, R).

single_element([_]).

final_filter([(A, B)|_], _):-
    write(A),
    P is A*B,
    S is A+B,
    get_all_products(P, PRODUCTS),
    get_all_sums(S, _),
    write(A),write(' '), write(B), write('\n'),
    not(single_element(PRODUCTS)).

1 个答案:

答案 0 :(得分:3)

这里的中心误解是Prolog中的终止意味着什么。也就是说,通用终止。感兴趣的查询如下:

?- get_all_sums(4,R).
R = [ (2, 2)] 

Prolog的顶级shell为您提供第一个答案。但是通过输入; SPACE 可以获得更多。所以当向您展示第一个答案/解决方案时,Prolog还没有完成。事实上:

?- get_all_sums(4,R).
R = [ (2, 2)] ;
R = [ (2, 2), (3, 1)] ;
R = [ (2, 2), (3, 1), (4, 0)] ;
R = [ (2, 2), (3, 1), (4, 0), (5, -1)] ;
R = [ (2, 2), (3, 1), (4, 0), (5, -1), (6, -2)] ;
R = [ (2, 2), (3, 1), (4, 0), (5, -1), (6, -2), (7, -3)] ;
R = [ (2, 2), (3, 1), (4, 0), (5, -1), (6, -2), (7, -3), (8, -4)] ;
R = [ (2, 2), (3, 1), (4, 0), (5, -1), (6, -2), (7, -3), (8, -4), (9, -5)] ...

你真的想要列举所有负数吗?对我来说看起来无穷无尽!

但是,让我们专注于非终止财产......

也许系统会在8个解决方案后停止?有没有更好的方法 当然?只需&#34;关闭&#34;解决方案的显示如下:

?- get_all_sums(4,R), false.

现在我们不再对解决方案/答案感到烦恼,我们可以专注于终止属性。我将进一步增加这些目标 false以及更多进入您的计划,以本地化不终止的实际原因。生成的程序称为故障切片。无论我如何添加false目标,它总是认为:如果失败切片没有终止,那么原始程序也不会终止。经过一番尝试,我得到了:

get_all_sums_R(NR, IT, []):- false, IT > NR - 2.
get_all_sums_R(NR, IT, R):- NR = 4,
    A is IT,
    B is NR-IT,
    A >= B,
    NEXT_IT is IT + 1,
    get_all_sums_R(NR, NEXT_IT, R_NEXT), false,
    append([(A, B)], R_NEXT, R).
get_all_sums_R(NR, IT, R):- false,
    A is IT,
    B is NR-IT,
    A < B,
    NEXT_IT is IT + 1,
    get_all_sums_R(NR, NEXT_IT, R).

get_all_sums(NR, R):-get_all_sums_R(NR, 2, R), false.

?- get_all_sums(4, R), false.

所以这个小的剩余部分负责不终止。为了解决这个问题,你必须在这里添加一些目标。确定:NR = 4A增加1,B减1。只要A >= B,这个循环就会继续。

您可能想要添加剪切或once/1。但是这个 只引导你从一个虫子到另一个虫子。更好地解决上述问题。