Проблема с бесконечным циклом Prolog

У меня есть следующие функции. Когда я вызываю его с помощью 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)).

person yonutix    schedule 09.11.2014    source источник
comment
Что вы ожидаете? get_all_sums(S, _). выдает ошибку создания экземпляра, а get_all_sums(4, R), false не завершается   -  person false    schedule 09.11.2014
comment
Я пробовал % d:/newl компилируется 0,00 сек, 14 пунктов 1 ?- get_all_sums(4, R). R = [(2, 2)] . 2 ?- get_all_sums(4, _). истинный .   -  person yonutix    schedule 09.11.2014


Ответы (1)


Основное недоразумение здесь заключается в том, что означает завершение в Прологе. То есть универсальное завершение. Интересует следующий запрос:

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

Оболочка верхнего уровня Пролога сначала предлагает вам единственный ответ. Но вы можете получить больше из них, введя ; или ПРОБЕЛ. Таким образом, Пролог не был закончен, когда показывал вам первый ответ/решение. Фактически:

?- 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 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 = 4, A увеличивается на 1, B уменьшается на единицу. И пока A >= B этот цикл будет продолжаться.

У вас может возникнуть соблазн добавить где-нибудь вырезку или once/1. Но это приведет вас только от одной ошибки к другой. Лучше решите проблему выше.

person false    schedule 09.11.2014