I'm currently trying to practice some Prolog. I just started and I'm facing a problem I don't quite understand. I want to determine recursively if one Peano number is the double of another one. I tried to solve it like this:
isDouble(0, X,X).
isDouble(s(Peano1), Peano1, Peano2) :-
isDouble(Peano1, s(Peano1), Peano2).
For some reason it doesn't work. Does anyone know why?
You don't need three arguments to define such a predicate. Just consider what relation it should describe: a relation between a number and its double. Hence you only need two arguments and two rules describing the two possibilities. Either the number is zero, then its double is zero as well. Otherwise you have a difference of two s/2 for the double in every recursion but only one for the number:
nat_double(0,0).
nat_double(s(X),s(s(Y))) :-
nat_double(X,Y).
This yields the desired results:
?- nat_double(X,Y).
X = Y, Y = 0 ; % X=0, Y=0
X = s(0), % X=1
Y = s(s(0)) ; % Y=2
X = s(s(0)), % X=2
Y = s(s(s(s(0)))) ; % Y=4
X = s(s(s(0))), % X=3
Y = s(s(s(s(s(s(0)))))) ; % Y=6
X = s(s(s(s(0)))), % X=4
Y = s(s(s(s(s(s(s(s(0)))))))) ; % Y=8
.
.
.
Or if you want to test a pair as suggested in the comments:
?- nat_double(s(s(0)),s(s(s(s(0))))).
true.
EDIT:
If you insist on the interface isDouble/3, as your comment suggests, then you could define it as a calling predicate for nat_double/2 like so:
isDouble(X,X,Y) :-
nat_double(X,Y).
That yields the desired result for your example:
?- isDouble(s(s(0)),s(s(0)),s(s(s(s(0))))).
true.
Related
I have understood the theory part of Recursion. I have seen exercises but I get confused. I've tried to solve some, some I understand and some I don't. This exercise is confusing me. I can't understand why, so I use comments to show you my weak points. I should have power (X,N,P) so P=X^N.
Some examples:
?- power(3,5,X).
X = 243
?- power(4,3,X).
X = 64
?- power(2,4,X).
X = 16
The solution of this exercise is: (See comments too)
power(X,0,1). % I know how works recursion,but those numbers 0 or 1 why?
power(X,1,X). % X,1,X i can't get it.
power(X,N,P) :- % X,N,P if only
N1 is N-1, % N1=N-1 ..ok i understand
power(X,N1,P1), % P1 is used to reach the the P
P is P1*X. % P = P1*X
What I know recursion, I use a different my example
related(X, Y) :-
parent(X, Z),
related(Z, Y).
Compare my example with the exercise. I could say that my first line, what I think. Please help me out with it is a lot of confusing.
related(X, Y) :- is similar to power(X,N,P) :- . Second sentence of my example parent(X, Z), is similar to N1 is N-1, and the third sentence is related(Z, Y). similar to power(X,N1,P1), and P is P1*X..
Let's go over the definition of the predicate step by step. First you have the fact...
power(X,0,1).
... that states: The 0th power of any X is 1. Then there is the fact...
power(X,1,X).
... that states: The 1st power of any X is X itself. Finally, you have a recursive rule that reads:
power(X,N,P) :- % P is the Nth power of X if
N1 is N-1, % N1 = N-1 and
power(X,N1,P1), % P1 is the N1th power of X and
P is P1*X. % P = P1*X
Possibly your confusion is due to the two base cases that are expressed by the two facts (one of those is actually superfluous). Let's consider the following queries:
?- power(5,0,X).
X = 1 ;
ERROR: Out of local stack
The answer 1 is certainly what we expect, but then the predicate loops until it runs out of stack. That's certainly not desirable. And this query...
?- power(5,1,X).
X = 5 ;
X = 5 ;
ERROR: Out of local stack
... yields the correct answer twice before running out of stack. The reason for the redundant answer is that the recursive rule can reduce any given N to zero and to one thus yielding the same answer twice. If you look at the structure of your recursive rule, it is obvious that the first base case is sufficient, so let's remove the second. The reason for looping out of stack is that, after N becomes zero, the recursive rule will search for other solutions (for N=-1, N=-2, N=-3,...) that do not exist. To avoid that, you can add a goal that prevents the recursive rule from further search, if N is equal to or smaller than zero. That leaves you with following definition:
power(X,0,1). % the 0th power of any X is 1
power(X,N,P) :- % P is the Nth power of X if
N > 0, % N > 0 and
N1 is N-1, % N1 = N-1 and
power(X,N1,P1), % P1 is the N1th power of X and
P is P1*X. % P = P1*X
Now the predicate works as expected:
?- power(5,0,X).
X = 1 ;
false.
?- power(5,1,X).
X = 5 ;
false.
?- power(5,3,X).
X = 125 ;
false.
I hope this alleviates some of your confusions.
I'm trying to define the function int(?X) in prolog which is a non-zero integer number generator which works like this:
?- int(X). X = 1 ; X = -1 ; X = 2 ; X = -2 ;
I tried the following with no luck:
int(X):- positives(Y), Y is abs(X).
positives(1).
positives(X):- positives(Y), X is Y+1.
but I'm getting the following error:
ERROR: is/2: Arguments are not sufficiently instantiated
How can I make this work? Thanks!
There is an easy way to find and correct such problems.
Step one: Put clpfd constraints in your program. To do this, simply1 replace (is)/2 by the CLP(FD) constraint (#=)/2, i.e.:
int(X) :- positives(Y), Y #= abs(X).
positives(1).
positives(X):- positives(Y), X #= Y+1.
Step two: The query now completes without errors, and shows you what you are describing:
?- int(X).
X in -1\/1 ;
X in -2\/2 ;
X in -3\/3 ;
X in -4\/4 .
So, from the above, you see that what you are describing is not sufficient to obtain ground solutions: There is still a certain degree of freedom in your relations.
Step three: To actually fix the problem, we think about what we actually want to describe. Here is a start:
int(X) :- positives(Y), ( X #= Y ; X #= -Y).
Step four: We try it out:
?- int(X).
X = 1 ;
X = -1 ;
X = 2 ;
X = -2 ;
X = 3 ;
etc.
Seems to work OK, except for the fact that natural numbers are actually never negative. I leave fixing this discrepancy between the title of your question and the relation you are describing as an exercise for you.
TL;DR: When reasoning over integers, use your system's CLP(FD) constraints, then take it from there.
I am assuming that you have already put :- use_module(library(clpfd)). somewhere in your initial file, so that you can use CLP(FD) constraints in all your programs.
I got the following task:
int_log2(X,Y) which sets Y to the integer log2 of X, where X is assumed to be a non-negative integer. For example int_log(133,X) will set X to 7. The integer log base 2 of X means the number of times you divide Xby 2 to get down to one. Where divide means integer division. Use nothing more than + and div to code it.
This is what I got so far. I am not 100% sure if I should do it like this. When I run query int_log(133,Z), it only shows answer in true or false.
div(0,X).
div(X,Z) :- X \=0, X1 is X-1, div(X1,W), Z is floor(X/2).
int_log(0,X).
int_log(X,Z) :- X \= 0, X1 is X-1, int_log(X1,W), div(W,Z).
As it is with such exercises, the problem statement already contains the answer.
X is assumed to be a non-negative integer
% precondition( integer(X) ).
% precondition( X > 0 ).
... the number of times you divide X by 2 to get down to one
int_log2(1, 0).
int_log2(X, Y) :-
... the number of times you divide X by 2...
... Use nothing more than + and div to code it.
X0 is X div 2, % used `div`
int_log2(X0, Y0),
Y is Y0 + 1. % used `+`
So this works like this:
?- int_log2(133, X).
X = 7 .
?- int_log2(256, X).
X = 8 .
?- int_log2(255, X).
X = 7 .
What will happen if you try to look for more solutions? Where does the choice point come from? How can you get rid of it? How can you get rid of it without using a cut?
Is this for a math course or a "Prolog" course? If it is meant to teach you Prolog, you will have a bad time.
As for how one would solve it: if you are using an implementation that has the arithmetic function msb(), you just say:
Y is msb(X).
for example:
?- X is msb(133).
X = 7.
?- X is msb(256).
X = 8.
just started programming with prolog and I'm having a few issues. The function I have is supposed to take a value X and copy it N number of times into M. My function returns a list of N number of memory locations. Here's the code, any ideas?
duple(N,_,M):- length(M,Q), N is Q.
duple(N,X,M):- append(X,M,Q), duple(N,X,Q).
Those are not memory adresses. Those are free variables. What you see is their internal names in your prolog system of choice. Then, as #chac pointed out (+1 btw), the third clause is not really making sense! Maybe you can try to tell us what you meant so that we can bring light about how to do it correctly.
I'm going to give you two implementations of your predicate to try to show you correct Prolog syntax:
duple1(N, X, L) :-
length(L, N),
maplist(=(X), L).
Here, in your duple1/3 predicate, we tell prolog that the length of the resulting list L is N, and then we tell it that each element of L should be unified with X for the predicate to hold.
Another to do that would be to build the resulting list "manually" through recursion:
duple2(0, _X, []).
duple2(N, X, [X|L]) :-
N > 0,
NewN is N - 1,
duple1(NewN, X, L).
Though, note that because we use >/2, is and -/2, ie arithmetic, we prevent prolog from using this predicate in several ways, such as:
?- duple1(X, Y, [xyz, xyz]).
X = 2,
Y = xyz.
This worked before, in our first predicate!
Hope this was of some help.
I suppose you call your predicate, for instance, in this way:
?- duple(3,xyz,L).
and you get
L = [_G289, _G292, _G295] ;
ERROR: Out of global stack
If you try
?- length(X,Y).
X = [],
Y = 0 ;
X = [_G299],
Y = 1 ;
X = [_G299, _G302],
Y = 2 ;
X = [_G299, _G302, _G305],
Y = 3 ;
X = [_G299, _G302, _G305, _G308],
Y = 4 .
...
you can see what's happening:
your query will match the specified *M*, displaying a list of M uninstantiated variables (memory locations), then continue backtracking and generating evee longer lists 'til there is stack space. Your second rule will never fire (and I don't really understand its purpose).
A generator is easier to write in this way:
duple(N,X,M) :- findall(X,between(1,N,_),M).
test:
?- duple(3,xyz,L).
L = [xyz, xyz, xyz].
The following code is a Prolog code which gives all integers greater than 0. Each time i put ; in the interpreter, it gives the next number:
is_integer(0).
is_integer(X) :- is_integer(Y),X is Y+1.
Is there a way where it gives numbers between 0 and 100 only. When it reaches 100 it should stop.
There is a built-in predicate between/3 for that purpose in B, Ciao, SICStus (library), SWI, YAP, XSB (library).
?- between(0,100,X).
X = 0
; X = 1
; ...
; X = 100.
If you start to learn Prolog, better try to use s(X) numbers first which are much easier to understand and reason about. The same example, but only going up to 3:
?- nat_nat_sum(N,_,s(s(s(0)))).
with the definition:
nat_nat_sum(0,I,I).
nat_nat_sum(s(I),J,s(K)) :-
nat_nat_sum(I,J,K).
What a nice quiz. It exemplifies very well how difficult can be to control the recursion with the minimal tools that Prolog defines. We must commit our solutions to values lower than the predefined limit, restricting the otherless unbound search:
is_integer(0).
is_integer(X) :-
is_integer(Y),
( Y >= 100, ! ; X is Y + 1 ).
Here is the trace output limiting the range to 3 (i.e. ... Y >= 3, ! ; ...)
?- is_integer(X).
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
true.