SICStus Prolog making product/3 rule from sum/3 - prolog

First of all, this is a homework question, so please just give me a hint!
%Here is a rule that defines sum/3 that returns yes if Z is sum of X and Y
sum(X,Y,Z) :-
Z is X + Y.
%How can I make product/3
product(X,Y,Z) :- % based on sum/3 above?
Also, how can write a query on product such that it returns the answer of X * Y and not that it's merely true?

Consider that in mathematics:
x * 0 = 0
x * y = x + x * (y - 1)
That should help you write your rules.
As for a query, you can use something like this to get a result like this:
?- product(5, 3, Result).
Result = 15 ?
yes
In short, if you have an unbound variable in a query, it tries to find a value for that variable such that the predicate succeeds.

Related

Prolog - adding two arguments, even if one is not a number

in Prolog, how should I proceed when I want to add two arguments, even if one is not a number. So for instance, if I enter add2args(1,2,R). the result should be R = 3. If I enter add2args(1,x,R). the result should be R=1+x.
So far I have this:
add_2args(X,Y,R):- number(X),number(Y), R is (X+Y).
Which allows me to add two numbers, but I don't know how I can get it to print out anything other than true and false if X and Y are not numbers which is normal since number(X) checks if X is a number or not. What other rule do I have to add to get the desired result?
Prolog will view an expression symbolically (as a Prolog term) unless explicitly evaluated with something like is/2. So the simplest way to do this in your case would be the following:
add_2args(X, Y, R) :-
( number(X), number(Y) % Both X and Y are numbers, then...
-> R is X + Y % Evaluate the expression
; R = X + Y % Else, just unify R with the expression
).
The R = X + Y will not evaluate the expression but only unify the term X + Y with R. This is also a nice "Prolog beginner's guide" illustration for the difference between =/2 and is/2. If you wrote, for example, R = 2 + 3, then did a write(R) you would see 2 + 3, not 5. You could subsequently do, Result is R which would then evaluate the expression R and yield Result = 5.
| ?- R = 2 + 3, Result is R.
R = 2+3
Result = 5
yes
| ?-

How can I assert facts about all List members in Prolog?

I'd like to assert facts about all members of a List in prolog, and have any resulting unification retained. As an example, I'd like to assert that each list member is equal to five, but none of the below constructs does this:
?- L=[X,Y,Z], forall(member(E,L), E=5).
L = [_h27057686,_h27057704,_h27057722]
X = _h27057686
Y = _h27057704
Z = _h27057722
yes
?- L=[X,Y,Z], foreach(member(E,L), E=5).
L = [_h27057686,_h27057704,_h27057722]
X = _h27057686
Y = _h27057704
Z = _h27057722
yes
I would like a way to pose the query such that X=5,Y=5, and Z=5.
There is a lot of terminology that you might be getting wrong, or I am misunderstanding you.
"Equal to" is not the same as "could unify", or "unify", but it depends how you mean it.
With SWI-Prolog, from the top level:
?- X == 5.
false. % the free variable X is not the integer 5
?- unifiable(X, 5, U).
U = [X=5]. % you could unify X with 5, then X will be 5
?- X = 5.
X = 5. % X unifies with 5 (and is now bound to the integer 5)
The comment by CapelliC already has the answer that you are most likely after: given a list of variables (either free or not), make so that each variable in the list is bound to the integer 5. This is best done by unification (the third query above). The maplist simply applies the unification to each element of the list.
PS. In case you are wondering how to read the maplist(=(5), L):
These three are equivalent:
maplist(=(5), [X,Y,Z])
maplist(=, [5,5,5], [X,Y,Z])
X=5, Y=5, Z=5
And of course X=5 is the same as =(X,5).

Basic PROLOG counting

I'm new to prolog I'm trying to write a predicate which counts the following:
the predicates name is s2int when given:
s2int(0,Y) it shoud "return" Y=0.
s2int(s(0),Y) => Y=1.
s2int(s(s(0)),Y) => Y=2.
s2int(S(s(s(0))),Y) => Y=3.
and so on..
here is what i tried to write(very poorly),
at first i tried this code:
s2intAux(0,Y).
s2intAux(X,Y):- X = s(Z) ,Y1 is Y+1, s2intAux(Z,Y1).
but whenever i try to run it by typing s2intAux(s(0),Y) i get an error saying :"ERROR: is/2: Arguments are not sufficiently instantiated"
i get that error well because Y is undefined.
then i tried this one:
s2intAux(0,Y).
s2intAux(X,Y):- X = s(Z) ,Y1 is Y+1, s2intAux(Z,Y1).
s2int(X,Y):- Y1 is 0, s2intA(X,Y1).
(i tried to start Y with the value zero but this one didn't work at all)
I've been stuck for a couple of hours now which is why I'm turning to you guys, please help!
thank you.
You need the following to resolve the most trivial case:
s2intAux(0,0).
This will cause s2intAux(0,Y) to be true when Y is instantiated to 0.
In your subsequent lines, you don't have a statement that resolves Z to 0 when you run out of the s(.). For that, you need to take care of the single s(0) case. Then you can do the general case:
s2intAux(X,Y) :- X = s(0), Y is 1.
s2intAux(X,Y) :- X = s(Z), s2intAux(Z,Y1), Y is Y1 + 1.
Note that on the general case, we have to traverse down to get to the Y is 1 before we can unravel back up and finally assign Y to Y1 + 1.
You can also write that first line as just:
s2intAux(s(0),Y) :- Y is 1.
Final answer looks like this:
s2intAux(0,0).
s2intAux(s(0),Y) :- Y is 1.
s2intAux(X,Y) :- X = s(Z), s2intAux(Z,Y1), Y is Y1 + 1.

deduction from two goals

Suppose I have such goals:
times(0,_,0). % zero times X is zero
times(X,Y,Z) :- times(Y,X,Z) ,!. % X * Y = Y * X
When I try to ask:
?- times(0,1,X).
I get the double answer :
X = 0 ;
X = 0.
Possibly because first answer is deduced from the fact and second - from the rule.
Question - how to make prolog to give only one answer instead of two ?
add a cut to 'confirm' the first choice:
times(0,_,0) :- !.
or ban the 0 from the second:
times(X,Y,Z) :- X \= 0, times(Y,X,Z).
I've deleted the cut, but leave it if there are more rules.
But I think the 'reflexivity' rule will put you in trouble, with undue recursion.

Prolog - Variable as operator

I have an operator stored in a variable Op and two integers are stored in X and Y. Now, I want to do something like (Z is X Op Y), but this syntax seems not to be correct.
Does anybody know if there is a way to do this in Prolog?
Thanks for your answers
you can do it by building the predicate using the =.. operator.
try it like:
compute(X,Y,Op,Z) :-
Eq=..[Op, X, Y],
Z is Eq.
An operator is really just like any other functor.
You can mimic the effect:
operator(Z,X,plus,Y):-Z is X + Y.
operator(Z,X,times,Y):-Z is X * Y.
I tried this on ideone.com for SWI-Prolog with:
OP=times, operator(Z,3,OP,8).
And I got:
OP = times,
Z = 24.

Resources