Adding integers in list - prolog

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).

Related

Prolog How to write a predicate sum 3 max values in list?

How to write a predicate sum 3 max values in list?
max3(L,X)
Example:
max3([1,7,9,3,5],X).
X = 21.
As a starting point:
% Can potentially change order of the list in Rest
list_max_rest([H|T], Max, Rest) :-
list_max_rest_(T, H, Max, Rest).
list_max_rest_([], Max, Max, []).
list_max_rest_([H|T], P, Max, [P|Rest]) :-
H #> P,
!,
list_max_rest_(T, H, Max, Rest).
list_max_rest_([H|T], P, Max, [H|Rest]) :-
list_max_rest_(T, P, Max, Rest).
Usage:
?- list_max_rest([2,1,200,9], Max, Res).
Max = 200,
Res = [1, 2, 9].
Use that 3 times...
max3(Ls, X) :-
select(A, Ls, Ls2),
select(B, Ls2, Ls3),
select(C, Ls3, Ls4),
A >= B,
B >= C,
\+ (member(Q, Ls4), Q > C),
X is A+B+C.
Take A from the list, B from the remainder, C from that remainder, they must be A>=B>=C, and there must not be a member Q left in the remainder which is bigger than C. Add those up.
This is not efficient; brebs' suggestion of:
max3(Ls, X) :-
sort(0, #>=, Ls, [A,B,C|_]),
X is A+B+C.
is neater

level([X|_], X, 1). how to get the level of a given value on a tree?

I've been trying to write a predicate to get the level of a given value on tree:
level([X|_], X, 1).
level([_, G, D], X, N) :-
level(G, X, N1),
level(D, X, N2),
max(N1, N2, N3),
N is 1 + N3.
But it return : false
why?
You do not state what happens if there is no such an element in your tree structure. One solution could be to add a "not available" atom to your code and toggle the cases accordingly.
For SWI Prolog:
max(na,na,na).
max(na,X,Y) :- dif(X,na), Y is X+1.
max(X,na,Y) :- dif(X,na), Y is X+1.
max(X,Y,Z) :- dif(X,na), dif(Y,na), Z is 1+max(X,Y).
level([], _, na).
level([X|_], X, 1).
level([_, G, D], X, N) :-
level(G, X, N1),
level(D, X, N2),
max(N1, N2, N).
Another way would be to use other functions instead of max or another attribute to your predicate to keep track of the current depth.

implementation of copy in prolog

Given a list of regs regs (1,2,3, ...) what I want the code to do is to copy the position X to X + 1, I put some examples below. I have the following code in prolog:
exe(EA, copy(X), ES):-
EA =.. [reg|TH],
LL1 is X+1,
length(TH,LL),
LL2 is LL+X+1,
length(L1,LL1),
length(L2,LL2),
append(L1,LI1,TH),[EX|L2]=LT1,
flatten(reg[L1,EX,L2], LR),
ES=.. LR.
what i want to show me as a result is:
?- exe(reg(1,2,3,4), copy(2), ES).
result:
?- ES=reg(1,2,2,4)
?- exe(reg(4,6,2,9), copy(1), ES).
result:
?-ES=reg(4,4,2,9).
?- exe(reg(1,2), copy(2), ES).
result:
false
I think the code is wrong
Try to split up your goal into multiple aspects, like: getting the element at position X (nth_element), then try to implement a predicate overwriting a particular value. Below is code that works as you expect. It basically traverses lists in the Prolog-"standard" way.
% Get the nth element of a list, indices starting at 1
nth_element([X|_], 1, X) :- !.
nth_element([_|Xs], N, R) :-
M is N - 1,
nth_element(Xs, M, R).
% Overwrites the N-th position in a list by a new element
% Indices starting with 1
% overwrite(List, N, Element, New_List) :-
% overwrite([], _, _, []) :- !.
overwrite([_|Xs], 1, Y, [Y|Xs]) :- !.
overwrite([X|Xs], N, Y, [X|Ys]) :-
M is N - 1,
overwrite(Xs, M, Y, Ys).
exe(EA, copy(X), Es):-
EA =.. [reg|TH],
nth_element(TH, X, Element),
Y is X + 1,
overwrite(TH, Y, Element, New),
Es =.. [reg|New].

ERROR: >/2: Arguments are not sufficiently instantiated

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).

Prolog Average Rules

The following set of Prolog rules work on an input such as average([3,4,5],A). Whereby A = 4.0.
However, if I try something like average([3,4,X],4). The following error is returned:
average([X|Xs],A) :- sum([X|Xs],S), length([X|Xs],L), {S/L=A}.
ERROR: is/2: Arguments are not sufficiently instantiated
How could I modify my code to allow average([3,4,X],4) to return the correct value for X?
The trivial solution with library(clpqr):
add(A, B, +(A,B)).
list_average([X|Xs], A) :-
length([X|Xs], Len),
foldl(add, Xs, X, Sum),
{Sum =:= A*Len}.
If for some reason you don't want to use the library, you can try the following code.
This will probably solve your problem, but I am not happy with this code. Certainly someone else knows better:
list_average(L, A) :-
( is_list(L)
-> length(L, Len),
term_variables(L-A, Vars),
solve(Vars, L, A, Len)
; instantiation_error(L)
).
solve([], L, A, Len) :-
sum_list(L, Sum),
A =:= Sum / Len. % Validate provided average
solve([X|Xs], L, A, Len) :-
partition(number, L, Nums, Vars),
length(Vars, T),
sum_list(Nums, Sum),
( var(A)
-> maplist(=(A), Vars), % all variables are as the average
A is Sum / (Len - T)
; maplist(=(X), Xs), % all free variables in list are same
X is (Len*A - Sum) / T
).
With this queries like this are possible:
?- list_average([2,3,4,5], A).
A = 3.5.
?- list_average([2,3,4,5], 3).
false.
?- list_average([2,X,4,5], 3).
X = 1.
?- list_average([2,X,4,Y], 3).
X = Y, Y = 3.
?- list_average([2,X,4,Y], A).
X = Y, Y = A, A = 3.
?- list_average([2,X,4,Y], 6).
X = Y, Y = 9.
It will automatically try to bind all free variables to a single free variable before solving numerically.
It's quite the same as Boris solution, but I use library lambda :
:- use_module(library(clpr)).
:- use_module(library(lambda)).
average(L, A) :-
length(L, Len),
foldl(\X^Y^Z^{Z = X+Y}, L, 0, TT),
{A * Len = TT}.
EDIT correction after false's remark.

Resources