2

I have the below functions. When I call it with final_filter([(2, 2)], R), it prints a lot of "2 2" pairs. When I comment get_all_sums(S, _) it works fine, however if I test separately get_all_sums(4, R). I works also fine, what could be the problem?

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

1 回答 1

3

这里的核心误解是终止在 Prolog 中的含义。也就是通用终止。感兴趣的查询如下:

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

Prolog 的顶级外壳首先为您提供了一个单一的答案。但是您可以通过输入;或获得更多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 个解决方案后停止?有没有更好的方法来确定?只需“关闭”解决方案的显示,如下所示:

?- 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是IT,
    B是NR-IT,
    A >= B,
    NEXT_IT 是 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 是 IT ,
     B 是 NR-IT ,
     A < B ,
     NEXT_IT 是 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. 但这只会将您从一个错误引导到另一个错误。更好地解决上面的问题。

于 2014-11-09T11:53:02.000 回答