Brand new to Prolog. I've played around with variable names and making sure variables have a calculated value, but I must be missing something. Could you all have a look and help me figure out what I'm missing?
lgstar(N,Answer) :- var(N) -> write('undefined'); lgstaranswer(N,Answer).
lgstaranswer(N1,Answer1) :- lgstarcompute(N1,Iterations),
var(Answer1) -> Answer1 is Iterations, write(Answer1);
(Answer1 is Iterations -> write('yes'); write('no')).
lgstarcompute(N2,Iterations1) :- N3 is floor(log10(N2)/log10(2)), write(N2), write(N3),
N3=<1 -> Iterations1 = 1;
lgstarcompute(N3,Iterations2),
Iterations1 is Iterations2+1.
You call lgstar() to kick things off. The errors I'm getting look as follows:
Arguments are not sufficiently instantiated
In:
[4] _672 is floor(... / ...)
[3] lgstarcompute(_738,_740) at line 7
[2] lgstarcompute(70000,_796) at line 9
[1] lgstaranswer(70000,4) at line 3
Working Code
Thanks to the accepted answer below, the code works. Please read their explanation. The following is working code for the whole function. Just keep in mind your professors know how to use Google!
lgstar(N,Answer) :- var(N) -> write('undefined'); lgstaranswer(N,Answer).
lgstaranswer(N1,Answer1) :- lgstarcompute(N1,Iterations),
((var(Answer1) -> Answer1 = Iterations);
(Answer1 == Iterations -> write('yes'); write('no'))).
lgstarcompute(N2,Iterations) :- N3 is floor(log10(N2)/log10(2)),
(N3 =< 1 -> Iterations = 1;
(lgstarcompute(N3,Iterations2), Iterations is Iterations2+1)).
It turns out this is a common mistake. You need to parenthesize your expressions due to operator precedence.
This is what you have:
lgstarcompute(N2,Iterations1) :- N3 is floor(log10(N2)/log10(2)), write(N2), write(N3),
N3=<1 -> Iterations1 = 1;
lgstarcompute(N3,Iterations2),
Iterations1 is Iterations2+1.
If I format that a bit nicer, I get:
lgstarcompute(N2, Iterations1) :-
N3 is floor(log10(N2)/log10(2)),
write(N2), write(N3),
N3 =< 1 -> Iterations1 = 1
;
lgstarcompute(N3, Iterations2),
Iterations1 is Iterations2+1.
In Prolog, at least in SWI Prolog, , is higher precendence than ->, which is higher than ;. So this is equivalent to:
lgstarcompute(N2, Iterations1) :-
(
(
N3 is floor(log10(N2)/log10(2)),
write(N2), write(N3),
N3 =< 1
) -> Iterations1 = 1
)
;
(
lgstarcompute(N3, Iterations2),
Iterations1 is Iterations2+1.
).
What happens is that when N3 =< 1 fails, Prolog backtracks all the way back to before N3 is floor(...) occurs to reach the most recent choice point and N3 is no longer instantiated. It then goes to the first query after the ; which is lgstarcompute(N3, Iterations2) with N3 uninstantiated.
To fix it, you need to group using parentheses:
lgstarcompute(N2, Iterations1) :-
N3 is floor(log10(N2)/log10(2)),
write(N2), write(N3),
( N3 =< 1
-> Iterations1 = 1
; lgstarcompute(N3, Iterations2),
Iterations1 is Iterations2+1
).
Now when N3 =< 1 fails, it won't backtrack to the write(N3) and all the way back to N3 is floor(...), but rather it will take the conjunction with N3 still instantiated.
Related
I am trying to print all the even numbers from 1 to 10 using Prolog, and here is what I have tried:
printn(10,0):- write(10),!.
printn(X,Sum):-
( X mod 2 =:= 0 -> Sum is X+Sum, Next is X+1, nl, printn(Next);
Next is X+1, printn(Next) ).
but it returns false.
You don't need to create the list with the numbers from the beginning, it is better to examine numbers once:
print(X,Y):-print_even(X,Y,0).
print_even(X, X, Sum):-
( X mod 2 =:= 0 -> Sum1 is X+Sum;
Sum1 = Sum
), print(Sum1).
print_even(X, Y, Sum):-
X<Y, Next is X+1,
( X mod 2 =:= 0 -> Sum1 is X+Sum, print_even(Next, Y, Sum1);
print_even(Next, Y, Sum)
).
Keep in mind that in Prolog Sum is Sum+1 always fails you need to use a new variable e.g Sum1.
Example:
?- print(1,10).
30
true ;
false.
The most useful way of obtaining Prolog output is to capture the solution in a variable, either individually through backtracking, or in a list. The idea of "printing", which carries over from using other languages allows for formatting, etc, but is not considered the best way to express a solution.
In Prolog, you want to express your problem as a relation. For example, we might say, even_with_max(X, Max) is true (or succeeds) if X is an even number less than or equal to Max. In Prolog, when reasoning with integers, the CLP(FD) library is what you want to use.
:- use_module(library(clpfd)).
even_up_to(X, Max) :-
X in 1..Max,
X mod 2 #= 0, % EDIT: as suggested by Taku
label([X]).
This will yield:
3 ?- even_up_to(X, 10).
X = 2 ;
X = 4 ;
X = 6 ;
X = 8 ;
X = 10.
If you then want to collect into a list, you can use: findall(X, even_up_to(X), Evens).
What error do you have? Here is my solution:
Create list [1...10]
Filter it, excluding odd numbers
Sum elements of the list
Code:
sumList([], 0).
sumList([Head|Tail], Sum) :-
sumList(Tail, Rest),
Sum is Head + Rest.
isOdd(X) :-
not((X mod 2) =:= 0).
sumOfEvenNums(A, B, Out) :-
numlist(A, B, Numbers),
exclude(isOdd, Numbers, Even_numbers),
sumList(Even_numbers, Out).
Now you can call sumOfEvenNums(1, 10, N)
In ECLiPSe, you can write with iterator:
sum_even(Sum):-
( for(I,1,10),fromto(0,In,Out,Sum)
do
(I mod 2 =:= 0 -> Out is In + I;Out is In)
)
With library(aggregate):
evens_upto(Sum) :-
aggregate(sum(E), (between(1, 10, E), E mod 2 =:= 0), Sum).
Thanks to #CapelliC for the inspiration.
I want to freeze my goal until some variable, for example list, is unbounded, right now I have
sieve(N,L) :-
freeze(Aux,sieve(N,L,[],Aux)),
numlist(2,N,Aux).
sieve(N,L,R,[H|T]) :-
freeze(X, X mod H =\= 0 ; X == H),
findall(X,select(X,T,_),P),
sieve(N,L,[H|R],P).
sieve(_,L,L,[]).
But it stop after some operations and waits forever. Could someone tell me how to correct this?
Ok i found out solution i had to change recursive call in sieve so now i call it in freeze predicate.
as requested
i found clue here Lazy lists in Prolog?
sieve(N,L) :-
sieve(L,Strumien,[]),
numlist(2,N,X),
X = Strumien.
sieve(L,Strumien,X) :-
freeze(Strumien,
( Strumien =[H|T],
filter(H,T,Z),
sieve(L,Z,[H|X])
)).
sieve(L,[],L).
filter(H,S,X) :-
filter(H,S,X,[]).
filter(_,[],X,X).
filter(H,S,X,Y) :-
freeze(S,S =[H1|T]),
( H1 mod H =\= 0 ->
append(Y,[H1],Y2),
filter(H,T,X,Y2)
;
filter(H,T,X,Y)
).
The issue is when I implement this problem :
for(+N1,+N2,+Step,N)
for(1,7,2,N).
N=1;
N=3;
N=5;
N=7
true
The code i have done is :
for(N1,_,_,N1).
for(N1,N2,Step,N):- N1 < N2, N1S is N1 + Step, for(N1S,N2,Step,N).
But when it runs it shows:
?- for(1,7,2,N).
N = 1 ;
N = 3 ;
N = 5 ;
N = 7 ;
false.
I think that in must show after N=7; the word True, but it appears false.
I think in the code i wrote, there is something i miss.
The false should not bother you; like #nhahtdh already pointed out, it is just there to inform you Prolog's backtracking engine ran out of paths.
But if you insist, it is possible to prevent the false, by using a cut.
for(N1, N2, Step, N1) :- N1 =< N2, N1 + Step > N2, !.
for(N1, N2, _, N1) :- N1 =< N2.
for(N1, N2, Step, N) :- N1S is N1 + Step, N1S =< N2, for(N1S, N2, Step, N).
Source: Can you write between/3 in pure prolog?
My teacher told me another an easier way for implementing with True at the end.
for(N1,_,_,N1).
for(N1,N2,Step,N):- N1 < N2, N1S is N1 + Step, for(N1S,N2,Step,N).
for(_,_,_,_).
I have just started prolog and was wondering if we can implement conditional statements like(if.else)in Prolog also and if so how??
Can someone implement this code in Prolog just for an example-
if(a==2)
print("A is 2");
if(a==3)
print("A is 3");
else
print("HAhahahahaah");
Ok so I am doing this after Sergey Dymchenko answer.
Test(A) :-read(A),
( A =:= 2 ->
write('A is 2')
;
( A =:= 3 ->
write('A is 3')
;
write('HAhahahahaah')
)
).
This is giving right answer except this is displaying A = 2 also which I dont want(If I give input 2).
One way to do it:
test(A) :-
( A =:= 2 ->
write('A is 2')
; A =:= 3 ->
write('A is 3')
; write('HAhahahahaah')
).
Another way to do it:
test(2) :-
write('A is 2').
test(3) :-
write('A is 3').
test(A) :-
A \= 2, A \= 3,
write('HAhahahahaah').
There are differences with these two codes, like choice points, behavior when A is not instantiated, and if A is treated as a number or not. But both will work the same way (except choice points left) and as expected with queries test(2)., test(3)., test(42).
I often used SWI-Prolog's feature of being able to do listing(predicate). to see how it implements some of its predicates. I want to see exactly what it does with succ/2 because I'm using it on SWI-Prolog but I need it running with Sicstus too which doesn't have it! I've seen what it does in the SWI manual, tried to implement it but I think it must do something extra to what I've tried. My problem is that the listing feature just gives
% Foreign: succ/2
Any ideas guys?
Thanks :).
The SWI version is probably implemented in C for better performance. Not being written in Prolog makes it foreign and probably considered a built-in.
Here's my stab at defining SWI's succ/2 in Prolog:
%%%% succ/2 to mimic the SWI Prolog built-in
succ(N0, N1) :-
( properly_grounded(N0)
-> N1 is N0 + 1
; properly_grounded(N1)
-> N1 > 0, N0 is N1 - 1
; otherwise
-> Ctx=context(succ/2,''),
throw(error(instantiation_error,Ctx))
).
properly_grounded(X):-
(var(X) -> false
;
( X >= 0
-> true
; otherwise
-> Ctx = context(succ/2,X),
E=domain_error(not_less_than_zero,X),
throw(error(E,Ctx));otherwise
)
).
If necessary, replace otherwise with true and false with fail. The code was developed in SWI, the context part of the exceptions may have to be adjusted for SICStus.
This question is super old, but here is a simple implementation that should have the same behavior as succ/2 in SWI-Prolog.
succ(X, Y) :- integer(X), Y is X + 1, X >= 0, !.
succ(X, Y) :- integer(Y), X is Y - 1, X >= 0.
We need both rules, because the right-hand side of is must be fully instantiated, and we check that with integer/1.