логика первого порядка, создающая термины для арифметических выражений с использованием prolog

#prolog #signature #predicate #first-order-logic

#prolog #подпись #предикат #логика первого порядка

Вопрос:

учитывая подпись (0,Z,{plus(2),minus(2),times(2)} , константы являются целыми числами, а функции — плюс, минус и раз с arity 2 для каждого. Я хотел написать два предиката arth/2 и printarth/1 который принимает термины в приведенной выше подписи и выполняет необходимые арифметические вычисления сложения, вычитания и умножения. arth/2 выведет результаты и printarth/1 должно вывести вычислительное выражение, как показано ниже.

Я хотел добиться двух вещей

Первый:

 ?- arth( plus(minus(8,2), times(4,-3)), N).
N = -6

N is evaluated as ((82)   (4∗−3)) = (612) =−6
  

второй:

 ?- printarth(plus(minus(8,2), times(4,-3)), N).
((8 - 2)   (4 * -3))
true.
  

Я понимаю Terms, Ops and complex terms , что для этого используется использование are, и запустил свой код, как показано ниже

 arithmetic_operator(' ').
arithmetic_operator('-').
arithmetic_operator('*').

arithmetic_expression(N) :- integer(N).

arithmetic_expression(Term) :-
    Term =..[Functor,Component1,Component2],
    arithmetic_operator(Functor),
    arithmetic_expression(Component1),
    arithmetic_expression(Component2).

  

Отсюда мне трудно понять, как создавать arth/2 , и printarth/1 поскольку я не могу вызвать arithmetic_expression(Term) и выдает мне ошибку, когда я ее вызываю.

 ?- arithmetic_expression(..[ ,5,7]).
ERROR: Syntax error: Operator expected
ERROR: arithmetic_expression(.
ERROR: ** here **
ERROR: .[ ,5,7]) .

  

любые ресурсы для этой задачи очень полезны.

Комментарии:

1. Очевидное недоразумение: вызывается предикат univ , определенный как оператор, и он выглядит так: =.. . Вы уже используете это в своем коде. Сам по себе = также является оператором (унификацией). Но .. само по себе это ничто.

Ответ №1:

Если вы хотите взять термин, который выглядит следующим образом:

 minus(2, 3)
  

и превратите его в арифметическое выражение -(2, 3) , эквивалентное 2 - 3 (с определением по умолчанию - как оператор), затем оцените его, вы могли бы сделать это следующим образом:

 term_arithmetic_expression(T, E) :-
    T =.. [Name, X, Y],
    binary_op(Name, Op),
    E =.. [Op, X, Y].

eval_arithmetic_expression(T, R) :-
    term_arithmetic_expression(T, E),
    R is E.

binary_op(minus, -).
% add more binary operations
  

Теперь это, по крайней мере, работает:

 ?- eval_arithmetic_expression(minus(2, 3), R).
R = -1.
  

Как вы видите, оба term_arithmetic_expression/2 и eval_arithmetic_expression/2 имеют два аргумента. Это то, что вам нужно сопоставить minus(2, 4) 2 - 4 .

Вы arithmetic_expression/1 правильно перемещаетесь, но не переходите из одного представления в другое. arithmetic_operator У вас та же проблема. С минимальными изменениями:

 arithmetic_operator(plus,  ).
arithmetic_operator(minus, -).
arithmetic_operator(times, *).

arithmetic_expression(N, N) :- integer(N).

arithmetic_expression(Term, Expr) :-
    Term =.. [Functor,Component1,Component2],
    arithmetic_operator(Functor, Operator),
    arithmetic_expression(Component1, Expr1),
    arithmetic_expression(Component2, Expr2),
    Expr =.. [Operator, Expr1, Expr2].
  

и затем:

 ?- arithmetic_expression(plus(minus(8,2), times(4,-3)), Expr).
Expr = 8-2 4* -3 ;
false.

?- arithmetic_expression(plus(minus(8,2), times(4,-3)), Expr),
   Result is Expr.
Expr = 8-2 4* -3,
Result = -6 ;
false.

?- arithmetic_expression(plus(minus(8,2), times(4,-3)), Expr),
   Result is Expr,
   display(Expr).
 (-(8,2),*(4,-3))
Expr = 8-2 4* -3,
Result = -6 ;
false.
  

Это то display , что выводится (-(8,2),*(4,-3)) в последнем запросе.

Комментарии:

1. ДА. Я намеревался написать арифметический термин, подобный вашей логике. Это работает для одного двоичного файла, но не работает, если я могу использовать более 1 двоичного файла с ошибкой «плюс / 2 не является функцией». почему это так?

2. @mkpisk вам нужно рекурсивно перевести каждый термин like minus(2, 4) в правильное арифметическое выражение like 2 - 4 ; затем вычислить с помощью is/2 . Вы можете либо вычислять по мере прохождения по дереву, либо создавать целое выражение, а затем оценивать его.

3. @mkpisk В вашем вопросе в основном выполняется обход. Просто исправьте переписывание, как показано в моем ответе. Вам нужно будет вычислить с is/2 помощью результата в вашем arth/2 ; просто не оценивайте его в своем arthprint/2 , чтобы получить выражение.

4. Спасибо @TA_intern, я попробую это сейчас

5. @mkpisk по крайней мере, вам пришлось бы добавить еще один аргумент к вашему arithmetic_expression . Первым аргументом может быть minus(times(...), ...) термин, второй аргумент будет результирующим x * y - ... .