Argument is not instantiated, need it to start at zero but also be able to change it

117 Views Asked by At

Whenever I run my code, I get an error that the arguments are not instantiated.

ads(X,Z):- mod(X,2) =:= 0, Z is Z+X.
ads(X,Z) :- mod(N,2) =\= 0,Z is Z.

sum_of_nums(0,0,0).
sum_of_nums(X,Y,Z) :-  X=<Y, ad(X,Z), sum_of_nums(X+1,Y,Z).

I want to be able to add numbers from X to Y but only the even ones. Don't know why it doesn't work.

1

There are 1 best solutions below

2
false On BEST ANSWER

First, there are some tiny errors, your compiler should indicate, like the unnecessary singleton variables in the second clause. After repairing this, and replacing ads by ad we have:

ad(X,Z):- mod(X,2) =:= 0, Z is Z+X.
ad(X,Z) :- mod(X,2) =\= 0,Z is Z.

sum_of_nums(0,0,0).
sum_of_nums(X,Y,Z) :-  X=<Y, ad(X,Z), sum_of_nums(X+1,Y,Z).

?- sum_of_nums(1,2,S).
   error(instantiation_error,(is)/2).

To locate this error, I will insert some goals false such that the resulting program still produces this instantiation error.

ad(X,Z):- mod(X,2) =:= 0, Z is Z+X, false.
ad(X,Z) :- false, mod(X,2) =\= 0,Z is Z.

sum_of_nums(0,0,0) :- false.
sum_of_nums(X,Y,Z) :-  X=<Y, ad(X,Z), false, sum_of_nums(X+1,Y,Z).

?- sum_of_nums(1,2,S).
   error(instantiation_error,(is)/2).

Therefore, you have an error in this part already.

It's the Z is Z+X. On the right hand side of (is)/2 you always need to have variables that are instantiated (known). And Z is not known.

Variables are a bit different in Prolog. You cannot reassign them.

And also, writing this in Prolog directly doesn't really show what the language is good at.

sum_of(X, Y, 0) :-
   X > Y.
sum_of(X1, Y, Z1) :-
   X1 =< Y,
   ( X1 mod 2 =:= 0 -> S = X1 ; S = 0 ),
   X2 is X1+1,
   sum_of(X2, Y, Z2),
   Z1 is Z2+S.

A more idiomatic way would be:

?- between(1,6,N).
   N = 1
;  N = 2
;  N = 3
;  N = 4
;  N = 5
;  N = 6.
?- between(1,6,N), N mod 2 =:= 0.
   N = 2
;  N = 4
;  N = 6.
?- findall(N, ( between(1,6,N), N mod 2 =:= 0 ), Ns).
   Ns = [2,4,6].
?- findall(N, ( between(1,6,N), N mod 2 =:= 0 ), Ns), sum_list(Ns,Sum).
   Ns = [2,4,6], Sum = 12.

sum_of(X,Y,Sum) :-
   findall(N, ( between(X,Y,N), N mod 2 =:= 0 ), Ns),
   sum_list(Ns,Sum).