#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 ((8−2) (4∗−3)) = (6 −12) =−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)
в правильное арифметическое выражение like2 - 4
; затем вычислить с помощьюis/2
. Вы можете либо вычислять по мере прохождения по дереву, либо создавать целое выражение, а затем оценивать его.3. @mkpisk В вашем вопросе в основном выполняется обход. Просто исправьте переписывание, как показано в моем ответе. Вам нужно будет вычислить с
is/2
помощью результата в вашемarth/2
; просто не оценивайте его в своемarthprint/2
, чтобы получить выражение.4. Спасибо @TA_intern, я попробую это сейчас
5. @mkpisk по крайней мере, вам пришлось бы добавить еще один аргумент к вашему
arithmetic_expression
. Первым аргументом может бытьminus(times(...), ...)
термин, второй аргумент будет результирующимx * y - ...
.