Count sum of spaces between first element and a specific element prolog - prolog

Basically trying to figure out how you would make a predicate where given two parameters, a list and a number, you would sum up the amount of spaces from the first element to the specific letter.
Example, say 'w' is the letter, given the statement
h1([e,w,b,a,w,w,c], 10)
would return true since 10 = 1+4+5 where 1,4,5 are the distances from element 0 and would return false if not 10.
Heres what I have so far
h2(List, H) :- sum(List,0,H).
sum([],TotalCount,TotalCount):- !.
sum([w|T],CurrentCount, TotalCount) :-
NewCount is CurrentCount + CountSince,
sum(T, NewCount, 0)
sum([_|T], NewCount, 0) :-
CountSince is CountSince + 1,
sum(T, NewCount, CountSince).

As said in the comment, you can solve this problem with three lines of code, using findall/3 and sum_list/2. Here the code:
h2(L,E,V):-
findall(P,nth0(P,L,E),LP),
( LP = [] -> false;
sum_list(LP,V)).
I wrote h2/3 and not h2/2 to make it more modular (i.e. you can pass the element you want to find to the predcate). Since you want false as answer if the element is not in the list, i've added an if statement to check if the list from findall/3 is empty. If it's not, simply sum the elements with sum_list/2.
?- h2([e, w, b, a, w, w, c],f,V).
false
?- h2([e, w, b, a, w, w, c],w,V).
V = 10

Related

How to "return" two values in prolog

I have two functions, first one calculates how many negative elements are in list, the second one forms list with indexes of negatives elements. I need to write a function called goal_negative_positions, that will "return" two values. My version don't work, it always returns false. How to make it correct?
negative_count([], 0):-!.
negative_count([Head|Tail], Count):-
Head >= 0, !,
negative_count(Tail, Count).
negative_count([_Head|Tail], Count):-
negative_count(Tail, TailCount),
Count is TailCount + 1.
negative_positions([], _, []):-!.
negative_positions([Head|Tail], CurPos, Positions):-
NextPos is CurPos + 1, (
Head >= 0, !,
negative_positions(Tail, NextPos, Positions);
negative_positions(Tail, NextPos, TailPositions),
Positions = [NextPos|TailPositions]
).
goal_negative_positions([], [], 0).
goal_negative_positions(Start, Result, count):-
negative_count(Start, count),
negative_positions(Start, -1, Result).
Problem in last definition of goal_negative_positions. count argument should starts with capital letter:
goal_negative_positions(Start, Result, Count):-
negative_count(Start, Count),
negative_positions(Start, -1, Result).
In prolog arguments which starts with small letter a working like constant. In your case goal_negative_positions(Start, Result, count) will be true if in negative_count(Start, Count) Count will be equal count.

Is there any way to check whether input n is less than or equal to length of list?

I am new to prolog, I wish to get a function:
drop(N, X, Y) that prints list Y which is the list X with its Nth element removed. If X does not have an Nth element then the predicate should fail.
Example:
1)drop(2,[1,2,3,4,5,6],Y) should give Y=[1,3,4,5,6].
2)drop(8,[1,2,3,4,5,6],Y) should fail.
I tried to get a function that appends an element of X to Y if it is not an Nth element and skips the element if it is an Nth element. Please see the following code:
drop(N,X,Y) :- integer(N),N>0,drop(X,1,N,Y).
drop([], _ , _ , [] ) .
drop( [X1|X] , P , N , [X1|Y] ) :- N=\=P , P1 is P+1 , drop(X,P1,N,Y) .
drop( [_|X] , P , N ,Y) :- N =:= P , P1 is P+1 , drop(X,P1,N,Y) .
The problem arises if N is greater than the length of the list, my code will print the entire list, but the function is supposed to fail in this case. I am not able to find a way to compare N with the length of the list since every function in prolog returns a binary value(according to my knowledge).
Any help will be much appreciated!
You are quite close. There are two things that you should change here:
once we have reached the correct index, we should no longer recurse on drop but just return the rest of the list; and
you should remove the drop([], _, _, []) line, since given we dropped an element, we will no longer recurse (see previous point).
Note that we can each time decrement the value for N and thus prevent using two variables. Like:
drop(N, X, Y) :-
integer(N),
drop_(N, X, Y).
drop_(1, [_|T], T).
drop_(N, [X|T], [X|T2]) :-
N > 1,
N1 is N-1,
drop_(N1, T, T2).

Recursivity | Natural numbers in list swish prolog

i have the next problem,
"return the numbers of natural numbers of an array"
ex. naturales(R,[6,-7,-4,3,2,8]).
R = 4
when a negative numbers appears return false and break my recursivity
naturales(R,[Head|Tail]):-naturales(R1,Tail), Head >= 0, R is R1+1.
naturales(0,[]).
Here is a very short solution :
naturales(In, Out) :-
aggregate(count,X^(member(X, In), X >= 0), Out).
If your predicate really needs to have only 2 arguments, one being the result, R, and the other one the given list, [H|T], you can do something like this. Note that the first predicate calls the second "naturales" with 3 arguments and then, that one starts the recursive process. The C is only a counter where you can add the number of positive elements and then copy that value to the result, in the last line of code. The first line just its just to make sure the empty list returns 0 positive elements. There is probably better ways to do this, this one is probably the most intuitive.
naturales(X, []):- X = 0.
naturales(R, [H|T]):- naturales(R, [H|T], 0).
naturales(R, [H|T], C):- (H > 0, C1 is C + 1, naturales(R1, T, C1), R = R1) ; naturales(R1, T, C), R = R1.
naturales(X, [], X).
A common prolog idiom is the use of a helper predicate with an accumulator (extra) variable. Try something like this:
natural_numbers( Xs, N ) :- natural_numbers( Xs, 0, N ).
natural_numbers( [] , N , N ) .
natural_numbers( [X|Xs] , T , N ) :-
( X > 0 -> T1 is T+1 ; T1 = T ) ,
natural_numbers( Xs, T1, N ).
As others pointed out, the recursive call cannot complete when there are negative numbers. So, you can just patch your program in this way
naturales(R,[Head|Tail]):-naturales(R1,Tail), (Head >= 0, R is R1+1 ; R=R1).
naturales(0,[]).
Now, nearly every Prolog out there (except mine :) implements (->)/2, also know as 'if-then-else'. So, the patch could also be written like
naturales(R,[Head|Tail]):-naturales(R1,Tail), (Head >= 0 -> R is R1+1 ; R=R1).
naturales(0,[]).
Given that naturales/2 is anyway not tail recursive (see #NicholasCarey answer for that), I think it has no practical relevance for you.

Summation of prolog predicates not working

Like the title states, I am trying to return the sum of the returned values from sub predicates but it's not working. Here is my code:
addlistnum([],[],X).
addlistnum(digits(Y,[A|T]),digits(F,[B|T]),X) :-
X is Y + F.
digits(Num, List) :-
digits(0, List, Num).
digits(Num, [], Num).
digits(N, [A|As], Num) :-
N1 is N * 10 + A,
digits(N1, As, Num).
The sub predicate works fine. It converts list to an integer. Now I want to sum the converted values.
Example:
?- digits(X,[3,3,3]).
X = 333. % works as expected
Building on that, addlistnum([3,3,3,3],[2,2,2],X) is supposed to produce X = 3555 (as 3555 is 3333 + 222), but I get false instead.
I also tried:
addlistnum([],[],X).
addlistnum([A|T],[B|T],X) :-
X is Y + F,
digits(Y,[A|T]),
digits(F,[B|T]).
It simply returns false, which gives no information about is wrong.
Problem is at these rules:
addlistnum([],[],X).
addlistnum(digits(Y,[A|T]),digits(F,[B|T]),X) :-
X is Y + F.
Second one is, "addition of two list is the addition of the integer conversion of these list":
addlistnum(A,B,X) :-
digits(NA,A),
digits(NB,B),
X is NA + NB.
first one is not necessary, "digits" for an empty list is zero, thus, this rule also covers "addition of two empty list is zero"

Prolog: Rotate list n times right

Working on a predicate, rotate(L,M,N), where L is a new list formed by rotating M to the right N times.
My approach was to just append the tail of M to its head N times.
rotate(L, M, N) :-
( N > 0,
rotate2(L, M, N)
; L = M
).
rotate2(L, [H|T], Ct) :-
append(T, [H], L),
Ct2 is Ct - 1,
rotate2(L, T, Ct2).
Currently, my code returns L equal to the original M, no matter what N is set to.
Seems like when I'm recursing, the tail isn't properly moved to the head.
You can use append to split lists, and length to create lists:
% rotate(+List, +N, -RotatedList)
% True when RotatedList is List rotated N positions to the right
rotate(List, N, RotatedList) :-
length(Back, N), % create a list of variables of length N
append(Front, Back, List), % split L
append(Back, Front, RotatedList).
Note: this only works for N <= length(L). You can use arithmetic to fix that.
Edit for clarity
This predicate is defined for List and N arguments that are not variables when the predicate is called. I inadvertently reordered the arguments from your original question, because in Prolog, the convention is that strictly input arguments should come before output arguments. So, List and N and input arguments, RotatedList is an output argument. So these are correct queries:
?- rotate([a,b,c], 2, R).
?- rotate([a,b,c], 1, [c,a,b]).
but this:
?- rotate(L, 2, [a,b,c]).
will go into infinite recursion after finding one answer.
When reading the SWI-Prolog documentation, look out for predicate arguments marked with a "?", as in length. They can be used as shown in this example.

Resources