Prolog is vs = with lists - prolog

Why does this fail L is [1,2,3,4], and this works: L = [1,2,3]?
But L is 1, and L = 1 both work the same.

is should only be used when evaluating arithmetic operations on the right-hand side.
i.e.:
X is 1 + 2 + 3
is/2 evaluates the right-hand structure as an arithmetic expression. If it is not a valid arithmetic expression or a number, is/2 fails. Otherwise, the number to which the arithmetic expression evaluted is unified with the [presumably] unbound left-hand value.

Related

Define operator in prolog

I am doing a lot of prolog exercises to improve my logic skills. But i'm stuck with the request of an exercise.
What i have to do is to define an operator i , in a way that: if the user inputs a complex number with this syntax , via the prompt ( so i use the read(X) operator)
(4+ i 7) - (2+ i 3).
i get as result
2+ i 4
I've understood how to define an operator in Prolog,i've studied the op operator but i dont know how make that subtraction operation really happen
Your first problem is that xfx defines a binary operator, and you want a unary operator, so you need a declaration like this:
:- op(600, xf, i).
Your second problem is that, there is no circumstance in which entering arithmetic expressions at the Prolog query prompt will result in anything like reduction happening automatically. See:
?- 3 + 4 * 7.
ERROR: Undefined procedure: (+)/2 (DWIM could not correct goal)
?- X = 3 + 4 * 7.
X = 3+4*7.
In order to cause arithmetic to be evaluated, you have to use the is/2 operator:
?- X is 3 + 4 * 7.
X = 31.
Try and think of is/2 as just another predicate, relating a numeric value with an expression. There is no way in ISO Prolog to modify the behavior of is/2, so you'll have to make an evaluation predicate of your own and use that:
eval((A + B i) + (C + D i), E + F i) :-
E is A + C,
F is B + D.
Once you have that, you can use it the usual way:
?- eval((3 + 4 i) + (7 + 8 i), X).
X = 10+12 i.
As you can see, this is probably going to get tedious, but it will work. If you want to gin up more comprehensive support for complex numbers by hand, you should consider making a metainterpreter.

Defining a mathematical language in prolog

So I have this mathematical language, it goes like this:
E -> number
[+,E,E,E] //e.g. [+,1,2,3] is 1+2+3 %we can put 2 to infinite Es here.
[-,E,E,E] //e.g. [-,1,2,3] is 1-2-3 %we can put 2 to infinite Es here.
[*,E,E,E] //e.g. [*,1,2,3] is 1*2*3 %we can put 2 to infinite Es here.
[^,E,E] //e.g. [^,2,3] is 2^3
[sin,E] //e.g. [sin,0] is sin 0
[cos,E] //e.g. [cos,0] is cos 0
and I want to write the set of rules that finds the numeric value of a mathematical expression written by this language in prolog.
I first wrote a function called "check", it checks to see if the list is written in a right way according to the language we have :
check1([]).
check1([L|Ls]):- number(L),check1(Ls).
check([L|Ls]):-atom(L),check1(Ls).
now I need to write the function "evaluate" that takes a list that is an expression written by this language, and a variable that is the numeric value corresponding to this language.
example:
?-evaluate([*,1,[^,2,2],[*,2,[+,[sin,0],5]]]],N) -> N = 40
so I wrote this:
sum([],0).
sum([L|Ls],N):- not(is_list(L)),sum(Ls,No),N is No + L.
min([],0).
min([L|Ls],N):-not(is_list(L)), min(Ls,No),N is No - L.
pro([],0).
pro([X],[X]).
pro([L|Ls],N):-not(is_list(L)), pro(Ls,No), N is No * L.
pow([L|Ls],N):-not(is_list(L)), N is L ^ Ls.
sin_(L,N):-not(is_list(L)), N is sin(L).
cos_(L,N):-not(is_list(L)), N is cos(L).
d([],0).
d([L|Ls],N):- L == '+' ,sum(Ls,N);
L == '-',min(Ls,N);
L == '*',pro(Ls,N);
L == '^',pow(Ls,N);
L == 'sin',sin_(Ls,N);
L == 'cos',cos_(Ls,N).
evaluate([],0).
evaluate([L|Ls],N):-
is_list(L) , check(L) , d(L,N),L is N,evaluate(Ls,N);
is_list(L), not(check(L)) , evaluate(Ls,N);
not(is_list(L)),not(is_list(Ls)),check([L|Ls]),d([L|Ls],N),
L is N,evaluate(Ls,N);
is_list(Ls),evaluate(Ls,N).
and it's working for just a list and returning the right answer , but not for multiple lists inside the main list, how should my code be?
The specification you work with looks like a production rule that describes that E (presumably short for Expression) might be a number or one of the 6 specified operations. That is the empty list [] is not an expression. So the fact
evaluate([],0).
should not be in your code. Your predicate sum/2 almost works the way you wrote it, except for the empty list and a list with a single element, that are not valid inputs according to your specification. But the predicates min/2 and pro/2 are not correct. Consider the following examples:
?- sum([1,2,3],X).
X = 6 % <- correct
?- sum([1],X).
X = 1 % <- incorrect
?- sum([],X).
X = 0 % <- incorrect
?- min([1,2,3],X).
X = -6 % <- incorrect
?- pro([1,2,3],X).
X = 6 ? ; % <- correct
X = 0 % <- incorrect
Mathematically speaking, addition and multiplication are associative but subtraction is not. In programming languages all three of these operations are usually left associative (see e.g. Operator associativity) to yield the mathematically correct result. That is, the sequence of subtractions in the above query would be calculated:
1-2-3 = (1-2)-3 = -4
The way you define a sequence of these operations resembles the following calculation:
[A,B,C]: ((0 op C) op B) op A
That works out fine for addition:
[1,2,3]: ((0 + 3) + 2) + 1 = 6
But it doesn't for subtraction:
[1,2,3]: ((0 - 3) - 2) - 1 = -6
And it is responsible for the second, incorrect solution when multiplying:
[1,2,3]: ((0 * 3) * 2) * 1 = 0
There are also some other issues with your code (see e.g. #lurker's comments), however, I won't go into further detail on that. Instead, I suggest a predicate that adheres closely to the specifying production rule. Since the grammar is describing expressions and you want to know the corresponding values, let's call it expr_val/2. Now let's describe top-down what an expression can be: It can be a number:
expr_val(X,X) :-
number(X).
It can be an arbitrarily long sequence of additions or subtractions or multiplications respectively. For the reasons above all three sequences should be evaluated in a left associative way. So it's tempting to use one rule for all of them:
expr_val([Op|Es],V) :-
sequenceoperator(Op), % Op is one of the 3 operations
exprseq_op_val(Es,Op,V). % V is the result of a sequence of Ops
The power function is given as a list with three elements, the first being ^ and the others being expressions. So that rule is pretty straightforward:
expr_val([^,E1,E2],V) :-
expr_val(E1,V1),
expr_val(E2,V2),
V is V1^V2.
The expressions for sine and cosine are both lists with two elements, the first being sin or cos and the second being an expression. Note that the argument of sin and cos is the angle in radians. If the second argument of the list yields the angle in radians you can use sin/1 and cos/2 as you did in your code. However, if you get the angle in degrees, you need to convert it to radians first. I include the latter case as an example, use the one that fits your application.
expr_val([sin,E],V) :-
expr_val(E,V1),
V is sin(V1*pi/180). % radians = degrees*pi/180
expr_val([cos,E],V) :-
expr_val(E,V1),
V is cos(V1*pi/180). % radians = degrees*pi/180
For the second rule of expr_val/2 you need to define the three possible sequence operators:
sequenceoperator(+).
sequenceoperator(-).
sequenceoperator(*).
And subsequently the predicate exprseq_op_val/3. As the leading operator has already been removed from the list in expr_val/2, the list has to have at least two elements according to your specification. In order to evaluate the sequence in a left associative way the value of the head of the list is passed as an accumulator to another predicate exprseq_op_val_/4
exprseq_op_val([E1,E2|Es],Op,V) :-
expr_val(E1,V1),
exprseq_op_val_([E2|Es],Op,V,V1).
that is describing the actual evaluation. There are basically two cases: If the list is empty then, regardless of the operator, the accumulator holds the result. Otherwise the list has at least one element. In that case another predicate, op_val_args/4, delivers the result of the respective operation (Acc1) that is then recursively passed as an accumulator to exprseq_op_val_/4 alongside with the tail of the list (Es):
exprseq_op_val_([],_Op,V,V).
exprseq_op_val_([E1|Es],Op,V,Acc0) :-
expr_val(E1,V1),
op_val_args(Op,Acc1,Acc0,V1),
exprseq_op_val_(Es,Op,V,Acc1).
At last you have to define op_val_args/4, that is again pretty straightforward:
op_val_args(+,V,V1,V2) :-
V is V1+V2.
op_val_args(-,V,V1,V2) :-
V is V1-V2.
op_val_args(*,V,V1,V2) :-
V is V1*V2.
Now let's see how this works. First your example query:
?- expr_val([*,1,[^,2,2],[*,2,[+,[sin,0],5]]],V).
V = 40.0 ? ;
no
The simplest expression according to your specification is a number:
?- expr_val(-3.14,V).
V = -3.14 ? ;
no
The empty list is not an expression:
?- expr_val([],V).
no
The operators +, - and * need at least 2 arguments:
?- expr_val([-],V).
no
?- expr_val([+,1],V).
no
?- expr_val([*,1,2],V).
V = 2 ? ;
no
?- expr_val([-,1,2,3],V).
V = -4 ? ;
no
The power function has exactly two arguments:
?- expr_val([^,1,2,3],V).
no
?- expr_val([^,2,3],V).
V = 8 ? ;
no
?- expr_val([^,2],V).
no
?- expr_val([^],V).
no
And so on...

prolog how to evaluate math expressions

I am studying for an exam and I am having trouble with the prolog section and this question in my book. I would like to create a predicate 'evaluate' that when given any expression sets the value to R. IE: A=4,B=5, evaluate(((A*B)-2)/3,R) it evaluates to R = 400. How would I go about creating this?
As #Dmitri Chubarov suggested you could use is/2:
evaluate(X,R):- R is X.
The above simply says R is the arithmetic result of X, so is/2 make all arithmetic operations and returns the arithmetic result.
Example:
?- A=4,B=5, evaluate(((A*B)-2)/3,R).
A = 4,
B = 5,
R = 6.

Why does 'is' in swi-prolog behave differently if sides are switched?

I'm using swi-prolog version 6.6.6 if that matters.
As far as I can tell they should be equivalent since the only difference is which side of the 'is' everything is on. Why do they give different results?
[trace] 48 ?- mod(3,3) is 0.
false.
[trace] 49 ?- 0 is mod(3,3).
true.
What every one else said. is/2 evaluates the right-hand side as an arithmetic expression and unifies the result of that evaluation (assuming that it was, in fact, a valid arithmetic expression, with the left hand side. So you can say things like:
X is 3+2 * 4 mod 3
0 is 3+2-5
And it's not really intended for arithmetic comparisons. But that would be clear if you had read the documentation for is/2:
-Number is +Expr
True when Number is the value to which Expr evaluates.
Typically, is/2 should be used with unbound left operand.
If equality is to be tested, =:=/2 should be used. For example:
?- 1 is sin(pi/2). Fails! sin(pi/2) evaluates to the float 1.0,
which does not unify with the integer 1.
?- 1 =:= sin(pi/2). Succeeds as expected.
And if you chase down the docs for =:=/2 and its relatives, you discover
+Expr1 > +Expr2.
True if expression Expr1 evaluates to a larger number than Expr2.
+Expr1 < +Expr2.
True if expression Expr1 evaluates to a smaller number than Expr2.
+Expr1 =< +Expr2.
True if expression Expr1 evaluates to a smaller or equal number to Expr2.
+Expr1 >= +Expr2.
True if expression Expr1 evaluates to a larger or equal number to Expr2.
+Expr1 =\= +Expr2.
True if expression Expr1 evaluates to a number non-equal to Expr2.
+Expr1 =:= +Expr2.
True if expression Expr1 evaluates to a number equal to Expr2.
A little curiousity won't hurt you.

What is best practices in Prolog when assigning a number to a variable?

To illustrate the difference between 'is' and '=', next example is given in my Prolog course:
?- X is 2+3
X = 5.
?- X = 2+3.
X = 2+3.
However, both Y is 3 and Y = 3 seem to do the same. Is there a difference? And if not, is there a convention not to use one of the two in Prolog programs?
In Prolog, =/2 and is/2 serve very different purposes. is/2 is used to assign a value from an arithmetic expression. The right hand side must be fully instantiated (all variables bound) and it will compute the expression and unify it with the single variable on the left. For example:
Y = 3,
X is log(Y+7)/2.
X = 1.151292546497023
Y = 3
The = is used to unify terms on each side of the =. So when you say:
X = log(Y+7)/2.
That is unifying the term X with the term log(Y+7)/2 (or, technically, '/'(log('+'(Y,7),2)) which gives you X = log(Y+7)/2. It doesn't compute log(Y+7)/2. because that's not the job of =. That's a job for is/2.
With = you can also say things like:
foo(X, _) = foo(3, blah).
And you will get X = 3 since it can unify both terms by setting X to 3.
In the simplest case, these operators appear to be the same because X is 3 evaluates the expression 3 and assigns it (binds it to) X, and X = 3 unifies X with 3. Both results are the same in this case.

Resources