How to "return" two values in prolog - 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.

Related

Double elements in list from N to N, code gives false

I have as input a list of numbers and I have to generate a new list with the elements from N to N doubled. For example:
?-double([1,2,3,4,5,6,7],2,L). returns L=[1,2,2,3,4,4,5,6,6,7] (in this case N=2)
?-double([1,2,3,4,5,6,7],3,L). returns L=[1,2,3,3,4,5,6,6,7] (in this case N=3)
I have come up with the following code:
double(List, N, L) :- double(List, N, 1, L).
double([], N, Index, L).
double([H|T], N, Index, [H,H|L]) :-
Index =:= N,
double(T,N,1,L).
double([H|T], N, Index, [H|L]) :-
Index =\= N,
newIndex is Index + 1,
double(T,N,newIndex,L).
Unfortunately, my code returns false. Can you guys point out the error? Thanks!
You have two typos in your code:
In the base case, replace L with [].
In the second recursive clause, replace newIndex with NewIndex.
I.e. When the input list is empty (or when reaching the end of the list after processing its elements), the output list will be also the empty list. Variables in Prolog start with an underscore or an upper case letter.

Count sum of spaces between first element and a specific element 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

How to get a rule to check all the conditions before exiting?

I'm trying to write a predicate weird_sum(List, Result) which takes a List of numbers, and computes the sum of the squares of the numbers in the list that are greater than or equal to 5, minus the sum of the absolute values of the numbers that are less than or equal to 2. For example:
?- weird_sum([3,6,2,-1], Result).
Result = 33
That's 6×6 - 2 - 1.
I'm trying to check using two conditions whether the number is >= 5 or <= 2. But whenever I call the predicate "computerResult" it will only check the first condition and exit. It never reaches the 2nd condition. How do I make it check the 2nd condition if it fails the first condition?
Here is my code:
%base case
weird_sum([], 0).
%figuring out if number is large or small
computeResult(Head, Result + Head*Head):-
Head >= 5.
computeResult(Head, Result - abs(Head)):-
Head #=< 2.
%recursive case
weird_sum([Head|Tail], Result):-
weird_sum(Tail, Result),
computeResult(Head,Result).
The problem is not that it does not try the second clause. The problem is the second parameter in the computeResult/2 predicate. You write Result + Head*Head, etc. so that means that Prolog will try to unify a number (0) with something of the form +(Result,*(Head,Head)) and this obviously fails.
You can however easily modify the result like:
%base case
weird_sum([], 0).
%recursive case
weird_sum([Head|Tail], Result) :-
weird_sum(Tail, SubResult),
computeResult(Head,Adder),
Result is SubResult+Adder.
%figuring out if number is large or small
computeResult(Head, Head*Head):-
Head >= 5.
computeResult(Head, -abs(Head)):-
Head =< 2.
computeResult(Head, 0) :-
Head < 5,
Head > 2.
You can also add cuts (!) to the conditions to prevent backtracking over the computeResult/2 clauses. In that case you can omit the checks in the last clause.
%figuring out if number is large or small
computeResult(Head, Head*Head):-
Head >= 5,
!.
computeResult(Head, -abs(Head)):-
Head =< 2,
!.
computeResult(_, 0).
Nevertheless it is more efficient to use an accumulator, like:
weird_sum(List, Result) :-
weird_sum(List, 0, Result).
weird_sum([], Result, Result).
weird_sum([Head|Tail], SubResult, Result) :-
computeResult(Head,Adder),
SubResult2 is SubResult+Adder,
weird_sum(Tail, SubResult2, Result).

Prolog - a program that finds a group of values that sum to a particular value

I want to make a program that receives 3 arguments:
list1 of coins for example: [5,2,1]
value - sum we want to get
list of coins that sum to that particular value - this list is a sub-list of list1
(it's allowed to repeat the same element , for ex: to reach 4, we can have the list [2,2])
so the program should do 2 things:
change([5,2,1],4,[2,2]) will return Yes (cause 2+2 =4)
change([5,2],6,Coins) will return Coins = [2,2,2]
this is my attempt:
change(_,0,Res).
change([X|Xs],Sum,Cs):- Sum <X, change(Xs,Sum,Cs).
change([X|Y],Sum,[X|Res]):- Sum>=X, Sum2 is Sum - X, change([X|Y],Sum2,Res).
You need to change Res to [] for the last argument of the first rule. In addition, you should add a cut operator in the same rule to avoid getting the same result multiple times.
change(_, 0, []):-!.
change([X|Y], Sum, [X|Res]):-
Sum >= X, !, % remove the cut operator to get all solutions
Sum2 is Sum - X,
change([X|Y], Sum2, Res).
change([_|Xs],Sum,Cs):-
change(Xs, Sum, Cs).
'guessing' an element from a list can be done with member/2.
Just pay care to termination
change(_,0,[]).
change(Coins,Sum,[C|Cs]) :-
Sum > 0, member(C, Coins), Rest is Sum-C, change(Coins,Rest,Cs).

Prolog Counter Problem

I am trying to write a procedure order(List,Result) that has a List as input and returns a list Result of ordered pairs such that:
the first element of the ordered pair is the position of the pair in the list, and
the second element of the ordered pair is the element from List n the corresponding position.
Example:
if List = [a,b,c,d], the procedure order(List,Result) outputs the list:
Result = [(1,a), (2,b),(3,c),(4,d)].
I am struggling with the counter for the position of the pair in the list. I have made attempts such as:
increment(Accum,Total):-
Total is Accum + 1.
order([],[]).
order([Head|Tail],Result):-
order(Tail, NewTail),
NewCount is Count + 1,
increment(NewCount,Count),
Result = [(Count,Head)|NewTail].
Please help anyone?
The two clauses: NewCount is Count + 1 and increment(NewCount,Count) basically have the same meaning. You didn't make clear that Count is an input variable and it has a base case of 1, so Prolog didn't know where to start unifying values for it. For example, you should use Count as an input argument as follows (it doesn't change much if compared with your version):
order([],[], _).
order([Head|Tail],[(Count,Head)|NewTail], Count):-
NewCount is Count + 1,
order(Tail, NewTail, NewCount).
order(List, Result ):- order(List, Result, 1).
If you're OK with using findall/3 then this is probably the simplest solution:
order(List, Result) :-
findall(Index-Elem, nth1(Index, List, Elem), Result).
Note that here the key-value pairs are represented using the term -/2, which is how pairs are usually represented in Prolog, e.g. this is what keysort/2 expects.
order(List,Result) :-
findall((N,E),(
append(L0,[E|_],List),
length([_|L0],N)),
Result).

Resources