Как получить полную остановку в этом предикате Пролога? - PullRequest
0 голосов
/ 11 февраля 2020

У меня есть следующий код:

factor_in_inches(Unit, Scale) :- recursiveScale(Unit, Scale, inch).

%Part3
scale_factor(Unit1, Unit2, Factor) :- recursiveScale(Unit2, Factor, Unit1).

%Part 1 - wrote alternate scale function so I could keep part instead of deleting for part 2 
findScale(Unit1, Scale, Unit2) :-
    scale(Unit1, Scale, Unit2);
    scale(Unit2, Scale1, Unit1),
    Scale is float(1/Scale1).

%need to flip scales because not all units have direct conversions to eachother
%have to find reciprocal conversion and then flip it

%Part2
%have to use findScale instead of regular scale because otherwise
%the recursive fucntion did not work for direct conversions to inches
%had to use findScale to get base conversions for inches
recursiveScale(Big, Scale, Smallest) :-
    findScale(Big, Scale, Smallest);
    recursiveScale(Smaller, MoreScale, Smallest),
    findScale(Big, ScaleAgain, Smaller),
    Scale is float(ScaleAgain * MoreScale).


%Part 4
convert(Unit1, Quantity1, Unit2, Quantity2) :-
    factor_in_inches(Unit1, Factor1),
    factor_in_inches(Unit2, Factor2),
    Factor1 is round((Factor2 * Quantity2)/ Quantity1).

И он основан на этих фактах:

scale(foot,    12, inch).
scale(yard,     3, foot).
scale(rod,    198, inch).
scale(chain,   22, yard).
scale(furlong, 40, rod).
scale(mile,     8, furlong).
scale(league,   3, mile).

Я пытаюсь запустить следующие тестовые случаи, чтобы проверить мой «конвертировать» предикат, но в третьем тесте он застревает на бесконечном l oop.

test(convert) :- convert(foot, 2,  inch,  24.0).
test(convert) :- convert(foot, 6,  yard,   2.0).
test(convert) :- convert(chain, 2, foot, 132.0).

Как бы я go остановил возврат, чтобы этот последний тест не работал бесконечно?

Спасибо.

Ответы [ 3 ]

3 голосов
/ 12 февраля 2020

Вот ответственная часть вашей программы, почему ни один из ваших запросов не прекращается. Это не только последний! Чтобы увидеть это, спросите Query, false вместо.

recursiveScale(Big, Scale, Smallest) :-
   (  <b>false</b>, <s>findScale(Big, Scale, Smallest)</s>
   ;  recursiveScale(Smaller, MoreScale, Smallest), <b>false</b>,
      <s>findScale(Big, ScaleAgain, Smaller)</s>,
      <s>Scale is float(ScaleAgain * MoreScale)</s>
   ).

factor_in_inches(Unit, Scale) :-
   recursiveScale(Unit, Scale, inch), <b>false</b>.

convert(Unit1, Quantity1, Unit2, Quantity2) :-
    factor_in_inches(Unit1, Factor1), <b>false</b>,
    <s>factor_in_inches(Unit2, Factor2)</s>,
    <s>Factor1 is round((Factor2 * Quantity2)/ Quantity1)</s>.

?- convert(chain, 2, foot, 132.0).

Этот фрагмент, называемый , тесно связан с вашей программой. Ибо, если этот фрагмент зацикливается, то ваша программа тоже будет l oop. Я получил этот фрагмент, просто добавив цели false в вашу программу. Интересно то, что все аргументы convert/4 эффективно игнорируются. Следовательно, все запросы будут l oop. Даже те, где вы полагали, что они заканчиваются.

Чтобы это исправить, вы должны изменить что-то в видимой части. Кажется, вы неправильно поняли дизъюнкцию. Всегда ставьте ; впереди или просто смотрите, что предлагает listing/1. Для получения дополнительной информации см. Тег .

0 голосов
/ 13 февраля 2020

Кажется, это может быть намного проще:

factor_in_inches(inch, 1) :- !.
factor_in_inches(Unit, Scale) :-
    scale(Unit, Scale1, Down),
    factor_in_inches(Down, Scale2),
    Scale is Scale1 * Scale2.

edit

Сокращение для эффективности, удаление его - то есть первое предложение становится

factor_in_inches(inch, 1).

Вы можете перечислить все факторы:

?- factor_in_inches(U,S).
U = inch,
S = 1 ;
U = foot,
S = 12 ;
U = yard,
S = 36 ;
U = rod,
S = 198 ;
U = chain,
S = 792 ;
U = furlong,
S = 7920 ;
U = mile,
S = 63360 ;
U = league,
S = 190080 ;
false.
0 голосов
/ 12 февраля 2020

В этой задаче нет оснований для того, чтобы что-либо работало бесконечно.

Вы бы просто уменьшили значение в некотором исходном номинале до "дюймов". Затем увеличьте значение в дюймах до целевого номинала.

scaling order

Предикат findScale/3 уже выглядит подозрительно. Вы хотите уменьшить, как в findScale(Big, Scale, Smallest). Однако третья строка пытается найти scale(Unit2, Scale1, Unit1), где Unit2 - это больший масштаб, чем Unit1. В базе данных такого факта не существует.

findScale(Unit1, Scale, Unit2) :-
    scale(Unit1, Scale, Unit2);
    scale(Unit2, Scale1, Unit1),
    Scale is float(1/Scale1).

То, что вам нужно, - это предикат

conversionFactor(U1,U2,F) :- larger(U1,U2),
                             stepDown(U1,Ux,Fx),
                             conversionFactor(Ux,U2,Fxx),
                             F is Fx*Fxx.
conversionFactor(U1,U2,F) :- larger(U2,U1),
                             conversionFactor(U2,U1,Fx),
                             F is 1.0/Fx.
conversionFactor(U1,U2,F) :- \+ larger(U1,U2), \+ larger(U2,U1), % incomparable
                             conversionFactor(U1,inch,Fa),
                             conversionFactor(inch,U2,Fb),
                             F is Fa*Fb.
conversionFactor(U,U,1.0).

Обратного отслеживания не существует, поскольку на самом деле выбора нет. Это просто рекурсивный вызов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...