ERROR: >/2: Arguments are not sufficiently instantiated - prolog

I want to get the length for the maximum sequence of even numbers but i get this error ERROR: >/2: Arguments are not sufficiently instantiated. I read something online but I can't understand.
Example:
max([2,4,6,7,4,8],R).
R=3
Here is my code:
max([H|T], L) :- max1(H, 1, T, L).
max1(H,_, [],0):-
H mod 2 =:=1.
max1(H, N, [], N):-
H mod 2 =:=0.
max1(X, N, [H|T], L) :-
X mod 2 =:=0,
M is N+1,
max1(H, M, T, L).
max1(X,N,[H|T],L):-
X mod 2 =:=1,
M>N,
max1(H, 1, T, M).
max1(X,N,[H|T],L):-
X mod 2 =:=1,
N>M,
max1(H,1,T,N).

In your last predicate max1, M isn't meaning anything. And in the predicate above you have the same problem because on the moment you are comparing M>N, M is also unknown.
I also don't understand why you are decoupling your list into X instead if immediately using [H|T]. Which simplifies the program.
Here is a solution that works with an accumulator.
max(L, R) :-
maxAcc(L, 0, 0, R). % list, currentBest, currentTot, Acc
maxAcc([],_, Best, Best).
maxAcc([H|T],Cur, Best, Acc) :-
H mod 2 =:=0,
CurN is Cur+1,
BestNext is max(CurN,Best),
maxAcc(T, CurN, BestNext, Acc).
maxAcc([H|T],Cur, Best, Acc) :-
H mod 2 =:=1,
BestNext is max(Cur,Best),
maxAcc(T, 0, BestNext, Acc).

Related

Truly Tail-Recursive modInverse() in Prolog

Rosetta code delivers me the following code snippet
for modinv/3. It does calculate extended GCD via egcd/4 and then
derives from it modinv/3:
egcd(_, 0, 1, 0) :- !.
egcd(A, B, X, Y) :-
divmod(A, B, Q, R),
egcd(B, R, S, X),
Y is S - Q*X.
modinv(A, B, N) :-
egcd(A, B, X, Y),
A*X + B*Y =:= 1,
N is X mod B.
Example queries:
?- modinv(42, 2017, N).
N = 1969.
?- modinv(42, 64, X).
false.
There is a slight problem with the solution. It is not
tail recursive. Namely the (is)/2 is the last call of
egcd/4 and not egcd/4 itself.
So the predicate might build-up a stack, a stack that
might contain large big numbers. How would one go about
and realize a more tail recursive solution?
The same site you mention has other algorithms amenable for a tail recursive solution.
Here I translated one from the C++ section (note there is a constraint missing in the original C++ code, it is not checking the last value of A):
modinv(A, B, N):-
modinv(A, B, 1, 0, N1),
(N1 < 0 -> N is N1 + B ; N1 = N).
modinv(A, B, X, Y, N):-
(B=0 -> (A=1, N=X) ;
(
divmod(A, B, Q, R),
Exp is X - Y * Q,
modinv(B, R, Y, Exp, N)
)
).
Sample queries:
?- modinv(42, 2017, N).
N = 1969.
?- modinv(42, 64, X).
false.

Prolog: why this predicate finds the answer but ignores it and goes on to unify with []?

I wrote a predicate that is supposed to traverse through a list of numbers and compare current number to the next one then adds the bigger number to a list that it is supposed to return. The last number is simply added to the list.
For example:
[1,2,3] should return [2,3,3]
[3,5,6,6,5,9] should return [5,6,6,6,9,9]
Problem
The predicate finds the answer (it writes it out), but it doesn't unify(?) with it and goes on to return [].
Code:
head([H|_], H).
head([],[]).
maximize([], X) :- write(X).
maximize([H|T], X) :-
(head(T, N), N = []) -> (append(X, [H], L), maximize([], L)) ;
(head(T, N), H < N) -> (append(X, [N], L), maximize(T, L)) ; (append(X, [H], L), maximize(T, L)).
A solution for the problem you describe is:
maximize([], []).
maximize([X| Xs], M) :-
maximize(Xs, X, M).
maximize([], X, [X]).
maximize([Y| Ys], X, M) :-
( Y > X ->
M = [Y| T]
; M = [X| T]
),
maximize(Ys, Y, T).
Sample calls:
| ?- maximize([1,2,3], M).
M = [2,3,3]
yes
| ?- maximize([3,5,6,6,5,9], M).
M = [5,6,6,6,9,9]
yes
This solution takes advantage of first-argument indexing to avoid spurious choice points.

Error counting occurrences in a list in Prolog

I trying to develop a small program in Prolog. Currently, I'm starting with Prolog and therefore there are issues that I do not understand well.
My program pretend to count the number of occurrences of an element in a list. In the end, it must to show next message: "Element X occurrs N times."
The code is as given below:
count_occur(X, [], N) :- format("Element ~d occurrs ~d times. ~n", [X,N]).
count_occur(X, [X|T], N) :-
count_occur(X, T, N2),
N is N2 + 1.
count_occur(X, [Y|T], N) :-
X \= Y,
count_occur(X, T, N).
Consulting with an example I always get following error:
?- count_occur(5,[2, 5, 5, 5, 6, 6, 8, 9, 9, 9], 0).
Element 5 ocurrs
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [19] format("Element ~d ocurrs ~d times. ~n",[5,_8398])
ERROR: [18] count_occur(5,[],_8428) at /Users/serrodcal/Repositories/PLExercises1/ex1.pl:1
ERROR: [11] count_occur(5,[5,6|...],_8456) at /Users/serrodcal/Repositories/PLExercises1/ex1.pl:3
ERROR: [10] count_occur(5,[5,5|...],_8496) at /Users/serrodcal/Repositories/PLExercises1/ex1.pl:3
ERROR: [9] count_occur(5,[5,5|...],0) at /Users/serrodcal/Repositories/PLExercises1/ex1.pl:3
ERROR: [7] <user>
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
I am using third params like counter but in the case base Prolog does not know the value of N.
If you insist on having that message printed, I would suggest to at least separate the output from the predicate describing the actual relation. Consider something along this pattern:
calling_predicate(...) :-
other_predicate(...), % <- predicate describing the actual relation
format(...). % <- output
You could, for instance, substitute count_occur/3 for calling_predicate and count_occur_/3 from #User9213's post for other_predicate. Alternatively you could opt for using CLP(FD) as suggested by #mat. Consider for example the following version using if_/3:
:- use_module(library(clpfd)).
count_occur(X, L, N) :-
list_x_count_(L,X,N,0), % <- actual relation
format("Element ~w occurs ~d times. ~n", [X,N]). % <- output
list_x_count_([],_X,N,N).
list_x_count_([Y|Ys],X,N,N0) :-
if_(Y=X,(N0 #< N, N1 #= N0+1), N1 #= N0),
list_x_count_(Ys,X,N,N1).
Since the elements in the list are not necessarily numbers, it is opportune to use the escape sequence ~w for the argument X instead of ~d (see the documentation of format/2 for more detail). If you query that with your given example, you get the desired result:
?- count_occur(5,[2,5,5,5,6,6,8,9,9,9], N).
Element 5 occurs 3 times.
N = 3.
Note that this query succeeds deterministically. That is, there are no superfluous choicepoints left, hence you don't need to enter ; after Prolog tells you the only answer. The example queries provided by #mat and #lambda.xy.x in the comments work as well:
?- count_occur(1,[2,X],0).
Element 1 occurs 0 times.
dif(X, 1).
?- count_occur(a, [a,b,c], N).
Element a occurs 1 times.
N = 1.
?- count_occur(X, [a,b,c], N).
Element a occurs 1 times.
X = a,
N = 1 ;
Element b occurs 1 times.
X = b,
N = 1 ;
Element c occurs 1 times.
X = c,
N = 1 ;
Element _G210 occurs 0 times.
N = 0,
dif(X, c),
dif(X, b),
dif(X, a).
I don't know how it can work like you have written it. Maybe write it like that:
count_occur(X, L, N) :- count_occur_(L, X, N).
count_occur_([], _, 0). % the 0 here is important (why?)
count_occur_([X|Xs], X, N) :-
count_occur_(Xs, X, N0),
succ(N0, N).
count_occur_([Y|Ys], X, N) :-
dif(Y, X),
count_occur_(Ys, X, N).
I found the error. The solution is:
count_occur(X, [], N) :- format("Element ~d occurrs ~d times. ~n", [X,N]).
count_occur(X, [X|T], N) :-
N2 is N + 1,
count_occur(X, T, N2).
count_occur(X, [Y|T], N) :-
X \= Y,
count_occur(X, T, N).
Second count_occur statement was wrong and it was not incrementing adequately.

Prolog list splitting

I tried this to solve problem of splitting list in lists of length 2^0, 2^2, 2^3 ... 2^n
split(L, X) :- split(L, 1, X).
split(X, N, [X]) :-
length(X, L),
L < N.
split(L, N, [X|Xs]) :-
length(X, N),
M = N * 2,
append(X, R, L),
split(R, M, Xs).
but I have problem:
ERROR: Type error: integer' expected, found1*2' (a compound)
ERROR: In:
ERROR: [12] throw(error(type_error(integer,...),context(...,_9654)))
I'm using SWI-Prolog and have no clue how to fix it. I will really appreciate if you could help me

Adding integers in list

For some reason, this is not working. I am getting:
ERROR: is/2: Arguments are not sufficiently instantiated
1 add_list([]).
2 add_list([H|T]):-
3 Sum2 is Sum1 + H,
4 add_list(T).
I am trying to add the contents of a list (containing only numbers).
I'm not sure what you are trying to do. But if you are trying to calc total sum it will be this way (changed name to list_sum as add_list doesn't make any sense):
list_sum([], 0).
list_sum([H|T], Sum):-
list_sum(T, SubSum),
Sum is SubSum + H.
You can have a "functionnal mind" with foldl :
foldl(_P, [], V, V).
foldl(P, [H|T], V1, VF) :-
call(P, H, V1, V2),
foldl(P, T, V2, VF).
sum_list(L, S) :-
foldl(add, L, 0, S).
add(X, Y, Z) :-
Z is X+Y.
Alternatively you could also use an accumulator (the advantage is, that it is tail-recursive and therefore can be optimized)
list_sum(L,R) :- list_sum(L,0,R).
list_sum([],A,A).
list_sum([H|T],A,R) :- A1 is A + H, list_sum(T,A1,R).

Resources