Как я могу избежать незавершения с целочисленным базовым случаем?

Я хочу написать предикат, который повторяется до 0, но он постоянно не завершается. Я использовал срез отказов, чтобы сузить его до этого:

f(a, 0).
f(b, 0).
f(X, Y) :- false.

Когда я загружаю файл как swipl -f test.pl, а затем запускаю f(X, 0). в подсказке, я получаю вывод X = a, но не вижу X = b и не получаю новую подсказку. Я ожидаю, что он будет действовать как A is 1 + 1, где я получаю A = 2. с точкой и новой подсказкой ?-.

Мне удалось заставить его работать с чем-то вроде этого, но это не кажется чистым:

f(X, 0) :- X = x.
f(X, Y) :- Y == 0 -> false; (NewY is Y - 1, f(X, NewY)).

Для списка я мог бы записать более общий случай как f(X, [A|B]), чтобы гарантировать, что он применяется только тогда, когда в списке есть хотя бы один элемент. Могу ли я сделать что-то подобное, чтобы гарантировать, что более общий случай здесь применим только тогда, когда Y не равен 0?

Я просмотрел этот вопрос, и хотя он намекает на правильное направление, это не тоже не работает:

:- use_module(library(clpfd)).

int_int_prod(_, 0, 0).
int_int_prod(Num1, Num2, Result) :- 
    Num2 #> 0,
    NewNum2 #= Num2 - 1,
    int_int_prod(Num1, NewNum2, NewResult),
    Result #= Num1 + NewResult.

?- int_int_prod(0, 0, X).

person Andrew    schedule 06.07.2018    source источник
comment
Можете ли вы опубликовать фактический нерабочий код? Я подозреваю, что что-то не так с вашим приложением разделения отказов (я действительно не понимаю, как может возникнуть незавершение в приведенных примерах), но я, вероятно, могу помочь отладить код, не применяя технику.   -  person Daniel Lyons    schedule 07.07.2018
comment
Код, который я разместил, не завершается для меня. Я получаю один вывод, X = x, но он не останавливается. Мне удалось заставить его работать, поэтому я отредактирую то, что сделал.   -  person Andrew    schedule 07.07.2018
comment
Что именно вы хотите, чтобы ваш предикат делал? Для рекурсии до 0 у вас будет базовый случай f(x, 0)., а ваш рекурсивный случай будет f(X, Y) :- Y > 0, Y1 is Y - 1, f(X, Y). или лучше, поскольку вы рассуждаете о целых числах, используя CLP(FD): f(X, Y) :- Y #> 0, Y1 #= Y - 1, f(X, Y).   -  person lurker    schedule 07.07.2018
comment
это тоже не работает... какой результат вы ожидаете и что получаете? Что означает отношение int_int_prod/3?   -  person lurker    schedule 07.07.2018
comment
да, Y > 1 (или Y #> 0) это аналог Y = [ _ | _ ].   -  person Will Ness    schedule 07.07.2018
comment
Я загрузил первый фрагмент, и он завершается на моей машине (без рекурсии он должен завершаться). Вы перезапустили интерпретатор Пролога и попробовали его без старого кода, оставшегося от предыдущих попыток? Предназначено ли тело первого предложения для объединения переменной X с константой x (обратите внимание на другой случай)? В таком случае лучше записать это как факт f(x, 0). или хотя бы переименовать переменную для ясности.   -  person lambda.xy.x    schedule 08.07.2018
comment
@lurker Я добавил подробности о том, чего я ожидаю и что получаю. Отношение int_int_prod взято из связанного вопроса, я просто показывал свое исследование.   -  person Andrew    schedule 09.07.2018
comment
@lambda.xy.x Я добавил описание того, что я ожидаю и что получаю. Я согласен, что первый пункт был некрасивым, я его переписал и вижу ту же проблему.   -  person Andrew    schedule 09.07.2018


Ответы (1)


Запустив f(X,0), вы получите X = a обратно. Обратите внимание на белое пространство. Система ждет вашей команды.

Если вы нажмете ; на клавиатуре, он ответит X = b. Это то, чего вы не хотите? (другой вариант: нажатие .). В конце концов, ваше определение допускает два решения этого запроса, X=a и X=b. Почему Пролог должен пропустить второй? Это не должно.

Другое дело, что он все равно ждет (проверено в SWI, загружается из подсказки через [user]) ответа пользователя после второго результата. Чтобы исключить это, просто удалите третье предложение. В любом случае это совершенно лишнее: явный сбой приводит к тому же эффекту, что и сбой, когда больше не удается найти подходящих предложений.

Без третьего предложения, f(X,Y) :- false., завершение улучшается:

6 ?- f(X,0).
X = a ;
X = b.
%   ^^    no white space, no waiting, immediate termination.
person Will Ness    schedule 09.07.2018
comment
Итак, я неправильно понял интерфейс. Спасибо! - person Andrew; 09.07.2018
comment
@AndrewPiliser Добро пожаловать! это действительно показывает важность правильного задания вопросов по SO, кстати. Если бы вы включили всю информацию с самого начала, вы бы получили ответ гораздо раньше. :) Счастливых троп! - person Will Ness; 10.07.2018
comment
завершение улучшается: это очень необычное использование слова завершение. Я бы скорее сказал, что такой пункт, как f(X,Y) :- false, вообще не меняет завершение. - person false; 08.02.2020