2

私は以下の機能を持っています。で呼び出すと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)).
4

1 に答える 1

3

ここでの中心的な誤解は、Prolog での終了の意味です。つまり、ユニバーサル ターミネーションです。対象のクエリは次のとおりです。

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

Prolog のトップレベル シェルは、最初に 1 つの答えを提供します。ただし、;またはを入力すると、さらに多くの情報が得られます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 = 4A1 増加し、1B減少します。である限りA >= B、このループは続きます。

どこかにカットを追加したくなるかもしれませんonce/1。しかし、これはあるバグから別のバグへと導くだけです。上記の問題に対処することをお勧めします。

于 2014-11-09T11:53:02.000 に答える