#prolog
Вопрос:
В настоящее время я пытаюсь улучшить использование рекурсии в прологе. Я не уверен, почему мне немного сложнее понять его, чем другие языки программирования. Для начала я хотел бы показать свой код с результатами.
eval_term([H|T], X, Y):- Y is X^T * H. eval_poly([],X,Y). eval_poly([H|T],X,Y):- eval_term(H, X, Y2), eval_poly(T, X, Y2). eval_poly([H|T],X,Y):- Y is Y2 Y, eval_poly(T,X,Y). ?- eval_poly([[1|2],[2|1],[3|0]],2, Y). true .
Выше у меня есть то, что у меня есть до сих пор из нескольких неудачных итераций. Я даю базовый случай с пустым списком, за которым следует числовое значение, которое заменит переменную(X) и предполагаемый результат(Y). Многочлен структурирован таким образом, что начало каждой пары является коэффициентом, а конец-показателем степени. Y должен выдавать 11 для предоставленных входных данных, но я, похоже, получаю только истину. Используя трассировку, я вижу, что он может правильно использовать eval_term (), но с этого момента я застрял. Любая помощь или подсказки будут высоко оценены!
Комментарии:
1.
eval_poly([H|T],X,Y):- Y is Y2 Y, eval_poly(T,X,Y).
используетY2
, но никогда не привязывает его к значению.2. Я думал, что это связано с переменной Y?
3.
is
Привязывается только левая сторона (если это еще не так). Кроме того, если бы это предложение действительно связывалоY2
, оно всегда связывало бы его с 0, предполагаяY is Y2 Y
, что на самом деле это ничего не дает.4. О, так, может быть, я заменю букву Y на Y2?
5.
Y2 is Y2 Y
? ИлиY is Y2 Y2
? Я не вижу, чтобы кто-то из них чего-то добился.
Ответ №1:
Чтобы правильно работать, ваш код нуждается в некоторых изменениях:
- Когда список, представляющий многочлен, пуст, независимо от значения второго аргумента, результат, полученный предикатом
eval_poly/3
, должен быть равен 0. Поэтому вам нужно изменить базовый вариант на:eval_poly([], _, 0).
- Поскольку значения созданных переменных не могут быть изменены, вам необходимо использовать новую переменную для каждого нового вычисленного значения. Поэтому вам нужно изменить рекурсивный регистр на:
eval_poly([H|T], X, Y):- eval_term(H, X, Y1), eval_poly(T, X, Y2), Y is Y1 Y2.
Помимо предложения , определяющего предикат eval_term/3
, для правильной работы предиката необходимы только эти два измененных eval_poly/3
предложения. Однако в вашем коде есть несколько моментов, которые можно улучшить:
- В прологе более идиоматично представлять пару как термин формы
First-Second
. Поэтому вы должны кодировать предикатeval_term/3
как:eval_term(Coefficient-Exponent, X, Y):- Y is Coefficient * X^Exponent.
- Кроме того, для большей эффективности вы можете избавиться от предиката
eval_term/3
и переопределить предикатeval_poly/3
, используя хвостовую рекурсию и накопитель:eval_poly(Terms, X, Y) :- eval_poly_loop(Terms, X, 0, Y). eval_poly_loop([], _, Acc, Acc). eval_poly_loop([Coefficient-Exponent|Terms], X, Acc, Y):- NewAcc is Acc Coefficient * X^Exponent, eval_poly_loop(Terms, X, NewAcc, Y).
- Запуск примеров:
?- eval_poly([1-2, 2-1, 3-0], 2, Y). % 1*x^2 2*x^1 3 Y = 11. ?- eval_poly([2-3, (-5)-1, 3-0], 3, Y). % 2*x^3 - 5*x 3 Y = 42.