Reputation: 305
I am new to Prolog and I have an issue using this code of finding if a number is prime.
finddivs(N,L) :- helpdivs(N,1,L).
helpdivs(N,I,L) :- I > N.
helpdivs(N,I,[Lm|Lk]) :-
N mod I =:= 0,
Lm is I, Ii is I + 1,
helpdivs(N,Ii,Lk).
helpdivs(N,I,L) :- Ii is I+1, helpdivs(N,Ii,L).
takefirst([M|_],M).
length([],0).
length([_|Lrst],N) :- length(Lrst,N1), N is N1+1.
is_prime(N) :- finddivs(N,L), write(L), nl,
length(L,P), write(P), nl, P =:= 2.
is_primeh(2).
?- is_prime(4), nl.
The result is:
.....
3
[1, 2, 4]
3
[1, 2, 4]
3
[1, 2, 4]
3
[1, 2, 4]The program is terminated.
I tried !,fail.
at the end of the function, but still doesn't help.
Can you explain me why this happens?
Upvotes: 1
Views: 201
Reputation: 58254
To codify this as an answer, the issue with the original implementation is that the predicate helpdivs
permits Prolog to backtrack into other clauses regardless of the value of I
.The following implementation will prevent Prolog from backtracking when you don't want it to by constraining the value of N
in each case:
helpdivs(N, I, L) :-
I > N.
helpdivs(N, I, [Lm|Lk]) :-
I =< N,
N mod I =:= 0,
Lm is I, Ii is I + 1,
helpdivs(N,Ii,Lk).
helpdivs(N, I, L) :-
I =< N,
N mod I =\= 0,
Ii is I+1,
helpdivs(N, Ii, L).
To make it a little more DRY, you can use the if-then-else:
helpdivs(N, I, _) :-
I > N.
helpdivs(N, I, L) :-
I =< N,
Ii is I + 1,
( N mod I =:= 0
-> L = [I|Lk],
helpdivs(N, Ii, Lk)
; helpdivs(N, Ii, L)
).
There are probably other similar variations on this theme that would work as well.
Upvotes: 1