2013-04-11 1 views
1

Я написал программу для вычисления выражения post-fix в прологе рекурсивно из списка выражений. Например, учитывая следующий список:Postfix expression list

[+,1,2] 

Он должен вернуться 3. Они, как я построил мой предикат называть себя рекурсивно до тех пор, пока не достигнет конца списка, так что он считывает значения в обратном направлении. (так же, как чтение этого списка слева направо: [2,1, +]).

Моя проблема заключается в том, что когда я пытаюсь вернуть более одного значения через рекурсивные вызовы, все значения внезапно исчезают.

Вот код:

eval_list([Head|Tail],_,Result):- 
    Tail==[], % last element of list 
    Result=Head, 
    write(Head), 
    write(' was stored in Result!\n'). 

eval_list([Head|Tail],Store1,Result):- 
     eval_list(Tail,Store2, NewResult), 
     (\+integer(Store2)) 
    -> 
     % if no integer is bound to Store2, bind Store1 to Head 
     Store1=Head, 
     Result is NewResult, 
     write(Head), 
     write(' is stored value!\n') 
    ; (integer(Store2)) -> 
    % if an integer is bound to store2, we perform operation specified by the Head with the stored number 
     X is Store2+NewResult, 
     Result is X, 
     write('performed operation!\n') 
    ; 
     % if doesnt catch either of these states the program is broken 
     ( print('something broke\n'), 
     print(Store1), 
     nl, 
     print(Store2), 
     nl, 
     print(Head), 
     nl, 
     print(Result), 
     nl 
    ). 

я получаю следующий результат:

?- eval_list([+,1,2],X,Result). 
2 was stored in Result! 
1 is stored value! 
something broke 
_G1162 
_L147 
+ 
_G1163 
true. 

Я не понимаю, почему мои ценности исчезают, или, если есть лучший способ оценить список.

ответ

6

Некоторые рекомендации по технике программирования. Вы должны использовать совпадение и унификацию головы вместо явной унификации в теле ваших определений предикатов, а конструкции if-else. Вы также должны избегать рекурсивной рекурсии хвоста, если только ваш алгоритм не является по сути рекурсивным (например, обход дерева в порядке). Это упростит чтение, чтение и понимание кода. Прямо сейчас, мне даже не хочется отлаживать ваш код, но похоже, что ваш Store2 никогда не будет привязан к целому числу и всегда будет несвязанной переменной, независимо от того, какой вклад имеет ваша программа.

Теперь в вашу программу. Неясно, чего вы пытаетесь достичь. Если вы хотите, чтобы оценить список формы [Arithmetic_operator, Operand1, Operand2], было бы гораздо проще написать:

arith_eval(Expression_list, Result) :- 
    Arithmetic_expr =.. Expression_list, % look up what =.. stands for! 
    Result is Arithmetic_expr. 

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

Если вы хотите, чтобы иметь возможность оценить сколь угодно сложные выражения, написанные в пост-фикса, с фиксированным оператором арностью (так что вы можете сказать 2, 3, +, но не 2, 4, 1, +, на сумму 7):

  • Прочитайте один элемент из вашего входа
    • Нажмите элемент в верхней части стека
    • Попробуйте уменьшить стек:
      • поп-оператор и операнды, если на вершине стек
      • оценить
      • толчок результат обратно на вершину стека
  • Когда вход пуст, ваш стек ваш результат

Вы можете явно определить эффект различные операторы (здесь, только + и -) примерно:

eval_stack([+,A,B|Tail],[Result|Tail]) :- 
    number(A), number(B), 
    !, 
    Result is B + A. 
eval_stack([-,A,B|Tail],[Result|Tail]) :- 
    number(A), number(B), 
    !, 
    Result is B - A. 
eval_stack(Stack,Stack). 

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

И вы можете нажать с вашего входа в свой стек:

evaluate([Next|Rest], Stack, Result) :- 
    eval_stack([Next|Stack],NewStack), 
    evaluate(Rest,NewStack,Result). 
evaluate([],Result,Result). % end of input 

Итак, теперь вы могли бы назвать это с:

?- evaluate([2,3,+,3,6,-,+],[],Result). 
Result = [2]. 

?- evaluate([2,3,4,-,-,5,+],[],Result). 
Result = [8]. 

?- evaluate([2,3,4,-,-,5,+,1,3,2,-],[],Result). 
Result = [1,1,8]. 

Таким образом, эти два предиката, evaluate(Input,Stack,Result) и eval_stack(Stack,NewStack) все, что бы необходимо оценить действительные арифметические выражения после исправления только с операторами фиксированной аргументации.

+0

Подход, который я пытался сделать, это обратить вспять постфиксное выражение, чтобы моя рекурсивная программа могла читать его назад справа налево: P Пример, который я дал, - это сделать вещи простыми ха-ха. Я хочу иметь возможность обрабатывать выражения любого размера. Как я понимаю, ваша версия программы сохраняет реорганизацию выражения до тех пор, пока оно не соответствует одному из предикатов eval_stack, где он затем заменяет раздел выражения результатом? Спасибо за ваш ответ, я пытался понять это на пару дней :) – thegalah

+1

@thegalah У меня это чувство тоже .... :), если нет ** очень ** веской причины для этого , всегда пытайтесь найти решение, которое читает список Prolog слева направо. Затем вы можете использовать унификацию, сопоставление и хвостовую рекурсию для естественной итерации по спискам. И да, но посмотрите мое редактирование на ответ (и проголосуйте, чтобы другие могли его использовать). – 2013-04-11 12:38:20

+0

[tag: DCG] кто-нибудь? – false

 Смежные вопросы

  • Нет связанных вопросов^_^