1

given a signature (0,Z,{plus(2),minus(2),times(2)}, constants are integers and functions are plus, minus and times with arity 2 for each. I wanted to write a two predicates arth/2 and printarth/1 which takes terms in the above signature and do the necessary arithmetic calculations addition, subtraction and multiplication.arth/2 will print the results and printarth/1 should results out the evaluation expression as shown below.

I wanted to achieve two things

first:

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

N is evaluated as ((8−2) + (4∗−3)) = (6 +−12) =−6

second:

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

I understand that the use of Terms, Ops and complex terms are used for this and started my code as below

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).

From here I find it difficult on how to create arth/2 and printarth/1 as I cannot call arithmetic_expression(Term) and throws me an error when I call it.

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

any resources on this task is very useful.

mkpisk
  • 152
  • 1
  • 9
  • The obvious misunderstanding: there is a predicate called `univ`, defined as an operator, and it looks like this: `=..`. You are using it already in your code. On its own, `=` is also an operator (unification). But `..` on its own is nothing. – TA_intern Oct 13 '20 at 06:11

1 Answers1

0

If you want to take a term that looks like this:

minus(2, 3)

and turn it into an arithmetic expression -(2, 3) which is equivalent to 2 - 3 (with the default definition of - as an operator), then evaluate it, you could do it like this:

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

Now this at least works:

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

As you see, both term_arithmetic_expression/2 and eval_arithmetic_expression/2 have two arguments. This is what you need to map minus(2, 4) to 2 - 4.

Your arithmetic_expression/1 is correctly traversing, but not mapping from the one representation to the other. Your arithmetic_operator has the same problem. With minimal changes:

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].

and then:

?- 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.

The display is what is outputting +(-(8,2),*(4,-3)) in the last query.

TA_intern
  • 2,222
  • 4
  • 12
  • Yes. I was intending to write an arithmetic term like your logic. It works for single binary_op but it fails if I can more than 1 binary_op with an error 'plus/2 is not a function'. why is it so? – mkpisk Oct 13 '20 at 09:42
  • @mkpisk you need to recursively translate every term like `minus(2, 4)` to a proper arithmetic expression like `2 - 4`; then evaluate using `is/2`. You could either evaluate as you traverse the tree or make the whole expression then evaluate that. – TA_intern Oct 13 '20 at 10:23
  • @mkpisk You have the traversal mostly done in your question. Just fix the re-writing as shown in my answer. You would have to evaluate with `is/2` for the result in your `arth/2`; just don't evaluate it in your `arthprint/2` to get the expression. – TA_intern Oct 13 '20 at 11:01
  • Thank you @TA_intern I will try it now – mkpisk Oct 13 '20 at 11:03
  • @mkpisk at least you'd have to add another argument to your `arithmetic_expression`. The first argument can be the `minus(times(...), ...)` term, the second argument would be the resulting `x * y - ...`. – TA_intern Oct 13 '20 at 11:05
  • I did not understand this. do you mean to replace T = ...[name.x.y] with the term I wanted? lets say plus(minus(),times()), if that is the case how can it work for more complex terms than that? I wanted to generalize the solution in such a way that it works for any terms based on the given signature – mkpisk Oct 13 '20 at 11:13
  • @mkpisk I don't know how to help you without showing the working code. Which is a pity because your code is _almost_ there... I will edit my answer. – TA_intern Oct 13 '20 at 11:28
  • Thank you very much. Yes it is a small change to my question. I appreciate for your changes :) – mkpisk Oct 13 '20 at 11:46
  • I wanted to check on the formatting of the final output of term. its currently results as 8-2+4* -3, how is it possible to get something like ((8-2)+(4* -3)) (notice its not the same as +(-(8,2),*(4,-3))). I have been trying to using various options (\k,\q) in format/2 predicate but nothing works. even I tried write_canonical and other write predicates, still no success – mkpisk Oct 15 '20 at 09:16
  • @mkpisk This is a whole new question. Don't ask new questions in comments. – TA_intern Oct 15 '20 at 13:06