list_sum([], 0).
list_sum([Head | Tail], TotalSum) :-
list_sum(Tail, Sum1),
Total = Head + Sum1.
This code returns true. If I replace Total = Head + Sum1 with Total is Head + Sum1, then it will return the value. But what I should replace it with to get the result like this:
?- list_sum([1,2,0,3], Sum).
Sum = 1+2+0+3 ; % not to return value 6!!!
The answer is simple:
sum_list([], 0).
sum_list([H|T], Sum) :-
sum_list(T, Rest),
Sum is H + Rest.
This code works in only one direction - this means - it does not allow you to generate lists with that specific sum. But since the set of such lists is infinite, that would not be practical anyways.
Note that in the second clause of your procedure TotalSum is never instantiated. You should have received a warning by the interpreter when consulting your code.
Here's my suggestion:
list_sum([Item], Item).
list_sum([Item1,Item2 | Tail], Total) :-
list_sum([Item1+Item2|Tail], Total).
The first clause deals with the base case, when there is only one element left in the list, that is your result.
The second clause deals with the recursion step. It grabs the first two items of the list and performs a recursive call replacing those two items with a new term Item1+Item2.
The program is
list_sum([],0).
list_sum([Head|Tail], TotalSum):-
list_sum(Tail, Sum1),
TotalSum is Head+Sum1.
now if the query is
?- list_sum([1,2,3,4], Sum).
answer is
Sum = 10
In Prolog (+)/2 is a binary infix operator. This allows us to write A+B instead of +(A,B).
?- current_op(_,yfx,+). % left-associative binary infix operator
true.
(+)/2 associates to the left, so 1+2+3 is a short for (1+2)+3.
(.)/2 associates to the right, so [1,2,3] is short for .(1,.(2,.(3,[]))).
To get parenthesization right, we use an auxiliary predicate with an extra "accumulator" argument:
list_sum([X|Xs],S) :-
list_sum0_sum(Xs,X,S).
list_sum0_sum([], S ,S).
list_sum0_sum([X|Xs],S0,S) :-
list_sum0_sum(Xs,S0+X,S).
Sample query:
?- list_sum([1,2,0,3],S).
S = 1+2+0+3.
If you want to transform a list of numbers into an additive expression, from
[1,2,3]
to
1 + 2 + 3
you could do something like this, using something like a difference list:
list_to_additive_expr( [] , 0 ).
list_to_additive_expr( [X|Xs] , X + RHS ) :-
sum_of( Xs , RHS ).
Alternatively, you could use an accumulator:
list_to_additive_expr( Xs , Expr ) :-
list_to_additive_expr( Xs , 0 , Expr )
.
list_to_additive_expr( [] , Expr , Expr ) .
list_to_additive_expr( [X|Xs] , RHS , Expr ) :-
sum_of( Xs , X + RHS , Expr )
.
I believe you'll find the first style is not properly tail recursive and so won't get optimized into a loop via tail recursion optimization (TRO) — and so, if the list is sufficiently long, will get a stack overflow. The second approach should have TRO applied and should work for lists of any length.
What is TRO, you might ask? Here's Wikipedia with an answer for you:
In computer science, a tail call is a subroutine call that happens inside another
procedure and that produces a return value, which is then immediately returned by the
calling procedure. The call site is then said to be in tail position, i.e. at the end of
the calling procedure. If a subroutine performs a tail call to itself, it is called
tail-recursive. This is a special case of recursion.
Tail calls are significant because they can be implemented without adding a new stack
frame to the call stack. Most of the frame of the current procedure is not needed any
more, and it can be replaced by the frame of the tail call, modified as appropriate
(similar to overlay for processes, but for function calls). The program can then jump to
the called subroutine. Producing such code instead of a standard call sequence is called
tail call elimination, or tail call optimization.
Related
I want to write a rule in Prolog that returns the even elements in a given list. For example:
even_elements([1,2,3,4], Result) would return Result: [2,4]
Here is what I have so far:
% This is my base case.
even_elements([H|T], Result) :- (0 is mod(H,2) -> Result = [H|T] ; Result = T).
% This is my recursion.
even_elements([H|T], [H|NT]) :- even_elements(T, NT).
The base case works properly and eliminates the first element if it is odd; but the recursion doesn't change anything. Any tips on how to complete the recursion is appreciated.
Often the base case in list processing deals with the empty list. Indeed, we can just write:
even_elements([], []).
For the recursive case, we can use quite a lot from your base case, the only thin that we still need to do is recurse on the tail of the list, so:
even_elements([H|T], Result) :-
( 0 is mod(H,2)
-> Result = [H|T2]
; Result = T2
),
even_elements(T, T2).
That being said, there is no need to implement the logic to filter a list. You can make use of the include/3 predicate [swi-doc], and thus define an even predicate:
even(N) :-
0 is N mod 2.
Then we can filter with:
even_elements(L, R) :-
include(even, L, R).
This then gives us:
?- even_elements([1,4,2,5], R).
R = [4, 2].
I also found this solution from this post although Willem's answer is way more readable:
even_elements(L1,L2):-findall(X,(member(X,L1), X mod 2=:=0),L2).
I'm trying to write a function that recursively adds the first two items in a List, and returns when one item remains.
Example:
addList([1,2,3,4], X)
x = [10]
(Steps here would be: [1,2,3,4] -> [3,3,4] -> [6,4] -> [10] )
This is what I have:
addList([],[]).
addList([H|[H2|T]], []) :- L is H+H2, addList(T, [L|T]).
addList([H|T], [H2|_]) :- L is H+H2, addList(T, [L|T]).
In my mind, this would do something like the following:
addList([1,2,3,4], X).
L=1+2 --> addList([3,4], [3,3,4])
L=3+3 --> addList([4], [6, 4])
L=6+4 --> addList([], [10])
This actually causes an error - "Arguments are not sufficiently instantiated"
If I make the first addList into addList([],[_])., it'll output X = [] . first, then have the same error if I use ; to continue.
It should end in false.
(After having the chain of X = [1,2,3,4] ; X = [3,3,4] ; X = [6,4] ; X = [10] ; false.
First, note that you can write [H|[H2|T]] equivalently as [H,H2|T].
Also, as far as I know in Prolog the preferred style is to use snake_case instead of camelCase.
add_list([H1,H2|T], []) :- ...
In the above clause, you already unifiy the second term with the empty list, and what happens in ... is just a way of checking if the relationship holds. The L that occurs in the body is only a local variable; likewise, the recursive call to add_list is not used to compute the "result" (the second parameter).
You expect the result to always be a singleton list containing the total sum of your values, except if the list is empty (in which case the result is empty). The base cases are then:
add_list([], []).
add_list([N], [N]).
The general case is necessarily something like:
add_list([H1,H2|T], [Sum]) :- ...
And you have to expression the recursive relationship in terms of H1, H2, T and Sum. In fact until you reach a base case you are likely to only pass down the second argument unmodified, so you do not need to write [Sum] explicitly, you could just write Res:
add_list([H1,H2|T], Res) :-
...,
add_list(..., Res).
New to prolog and trying to implement the following function that takes 3 lists:
True if lists are the same length
True if elements of third list is sum of the two lists
Example: fn([1,2,3],[4,5,6],[5,7,9]) returns true. Note that the sum is element-wise addition.
This is what I have so far:
fn([],[],[]).
fn([_|T1], [_|T2], [_|T3]) :-
fn(T1,T2,T3), % check they are same length
fn(T1,T2,N1), % check that T3=T1+T2
N1 is T1+T2,
N1 = T3.
From what I understand, the error is due to the base case (it has empty lists which causes error with evaluation of addition?)
Thanks for any help and explanations!
In addition to #GuyCoder's answer, I would point out that it is worthwhile to consider using one of the maplist predicates from library(apply) when modifying all elements of lists. You can use a predicate to describe the relation between three numbers...
:- use_module(library(apply)). % for maplist/4
num_num_sum(X,Y,S) :-
S is X+Y.
... and subsequently use maplist/4 to apply it to entire lists:
fn(X,Y,Z) :-
maplist(num_num_sum,X,Y,Z).
This predicate yields the desired results if the first two lists are fully instantiated:
?- fn([1,2,3],[4,5,6],X).
X = [5,7,9]
However, due to the use of is/2 you get instantiation errors if the first two lists contain variables:
?- fn([1,A,3],[4,5,6],[5,7,9]).
ERROR at clause 1 of user:num_num_sum/3 !!
INSTANTIATION ERROR- X is _+B: expected bound value
?- fn([1,2,3],[4,5,A],[5,7,9]).
ERROR at clause 1 of user:num_num_sum/3 !!
INSTANTIATION ERROR- X is A+B: expected bound value
If you only want to use the predicate for lists of integers, you can use CLP(FD) to make it more versatile:
:- use_module(library(apply)).
:- use_module(library(clpfd)). % <- use CLP(FD)
int_int_sum(X,Y,S) :-
S #= X+Y. % use CLP(FD) constraint #=/2 instead of is/2
fnCLP(X,Y,Z) :-
maplist(int_int_sum,X,Y,Z).
With this definition the previously problematic queries work as well:
?- fnCLP([1,A,3],[4,5,6],[5,7,9]).
A = 2
?- fnCLP([1,2,3],[4,5,A],[5,7,9]).
A = 6
Even the most general query yields results with this version:
?- fnCLP(X,Y,Z).
X = Y = Z = [] ? ;
X = [_A],
Y = [_B],
Z = [_C],
_A+_B#=_C ? ;
X = [_A,_B],
Y = [_C,_D],
Z = [_E,_F],
_A+_C#=_E,
_B+_D#=_F ? ;
.
.
.
Since the numbers in the above answers are not uniquely determined, you get residual goals instead of actual numbers. In order to get actual numbers in the answers, you have to restrict the range of two of the lists and label them subsequently (see documentation for details), e.g. to generate lists containing the numbers 3,4,5 in the first list and 6,7,8 in the second list, you can query:
label the lists
restrict the domain | |
v v v v
?- fnCLP(X,Y,Z), X ins 3..5, Y ins 6..8, label(X), label(Y).
X = Y = Z = [] ? ;
X = [3],
Y = [6],
Z = [9] ? ;
X = [3],
Y = [7],
Z = [10] ? ;
.
.
.
X = [3,4],
Y = [6,7],
Z = [9,11] ? ;
X = [3,4],
Y = [6,8],
Z = [9,12] ? ;
.
.
.
On an additional note: there are also clp libraries for booleans (CLP(B)), rationals and reals (CLP(Q,R)) that you might find interesting.
From what I understand, the error is due to the base case.
I don't see it that way.
The first problem I see is that you are trying to process list which leads to thinking about using DCGs, but since you are new I will avoid that route.
When processing list you typically process the head of the list then pass the tail back to the predicate using recursion.
e.g. for length of list you would have
ln([],N,N).
ln([_|T],N0,N) :-
N1 is N0+1,
ln(T,N1,N).
ln(L,N) :-
ln(L,0,N).
The predicate ln/2 is used to set up the initial count of 0 and the predicate ln/3 does the work using recursion. Notice how the head of the list is taken off the front of the list and the tail of the list is passed recursively onto the predicate again. When the list is empty the predicate ln([],N,N). unifies, in this case think copies, the intermediate count from the second position into the third position, which it what is passed back with ln/2.
Now back to your problem.
The base case is fine
fn([],[],[]).
There are three list and for each one look at the list as [H|T]
fn([H1|T1],[H2|T2],[H3|T3])
and the call to do the recursion on the tail is
fn(T1,T2,T3)
all that is left is to process the heads which is
H3 is H1 + H2
putting it all together gives us
fn([],[],[]).
fn([H1|T1], [H2|T2], [H3|T3]) :-
H3 is H1 + H2,
fn(T1,T2,T3).
and a quick few checks.
?- fn([],[],[]).
true.
?- fn([1],[1],[2]).
true.
?- fn([1,2],[3,4],[4,6]).
true.
?- fn([1,2],[3,4,5],[4,6,5]).
false.
With regards to the two conditions. When I look at exercises problems for logic programming they sometimes give a condition like True if lists are the same length or some other condition that returns true. I tend to ignore those at first and concentrate on getting the other part done first, in this case elements of third list is sum of the two lists then I check to see if the other conditions are correct. For most simple classroom exercises they are. I sometimes think teacher try to give out these extra conditions to confuse the student, but in reality the are there just to clarify how the code should work.
I want to count the number of elements in a list which have a relation with the element following.
The predicate I have works by using an accumulator variable which it increments if the predicate related returns true.
The following example code is to check the number of times an element is greater than it's previous element.
So for example
count_list([1,2,3,2,1,3,2],Count).
should return 3.
The code almost works. It increments the accumulator variable correctly. However, the function returns false, when it tries to compare the final 2 at the end with the non-existent next term.
listofitems([],N,N).
%count number of items which are related to the previous
listofitems([A,B|T],Acc,N) :-
write(A),write(' '), write(B),
( related(A,B) -> Acc1 is Acc+1 ; Acc1 = Acc ),
write(Acc1),write('\n'),
listofitems([B|T],Acc1,N).
count_list(L,N):-
listofitems(L,0,N).
%define the relationship to be counted
related(A,B):-
B>A.
Does anyone have any suggestions as to how to create an elegant terminating condition so I can return the accumulated value?
Does anyone have any suggestions as to how to create an elegant terminating condition so I can return the accumulated value?
The problem you have is that your query fails. Try first to minimize the query as much as possible. Certainly, you expect it to work for:
?- listofitems([], Count).
Count = 0.
Yet, it already fails for:
?- listofitems([1], Count).
false.
So let's try to dig into the reason for that.
And since your program is pure (apart from those writes), it is possible to diagnose this a little better by considering a generalization of your program. I prefer to look at such generalizations as I do not want to read too much (eye strain and such):
:- op(950, fy, *).
*_.
listofitems([], N,N).
listofitems([A,B|T], Acc,N) :-
* ( related(A,B) -> Acc1 is Acc+1 ; Acc1 = Acc ),
* listofitems([B|T], Acc1,N).
count_list(L,N):-
listofitems(L,0,N).
?- count_list([1], Count).
false.
Even this generalization fails! So now in desperation I try to ask the most general query. It's like when I ask one thing after the other and get a noe after a no. Good this is Prolog, for we can ask: "Say me just everything you know".
?- count_list(Es,Count).
Es = [], Count = 0
; Es = [_,_|_].
So it is only the case for the empty list and lists with at least two elements. But there is no answer for one-elemented lists! You will thus have to generalize the program somehow.
A natural way would be to add a fact
listofitems([_], N, N).
As a minor remark, this isn't called a "terminating condition" but rather a "base case".
And if you really want to trace your code, I recommend these techniques instead of adding manual writes. They are much too prone to error.
If the all list items are integers and your Prolog system supports clpfd, you can proceed like this:
:- use_module(library(clpfd)).
:- use_module(library(lists), [last/3]).
:- use_module(library(maplist), [maplist/4]).
To relate adjacent items, look at two sublists of [E|Es], Es and Fs. If, say,
[E|Es] = [1,2,3,2,1,3,2] holds ...
... then Fs lacks the last item (Fs = [1,2,3,2,1,3,2]) ...
... and Es lacks the first item (Es = [1,2,3,2,1,3,2]).
maplist/4 and i0_i1_gt01/3 map corresponding list items in Fs and Es to 0 / 1:
i_j_gt01(I, J, B) :- % if I #< J then B #= 1
I #< J #<=> B. % if I #>= J then B #= 0
?- maplist(i_j_gt01, [1,2,3,2,1,3], [2,3,2,1,3,2], Bs).
Bs = [1,1,0,0,1,0].
Last, sum up [1,1,0,0,1,0] using sum/3:
?- sum([1,1,0,0,1,0], #=, N).
N = 3.
Let's put it all together!
count_adj_gt([E|Es], N) :-
last(Fs, _, [E|Es]), % or: `append(Fs, [_], [E|Es])`
% or: `list_butlast([E|Es], Fs)`
maplist(i_j_gt01, Es, Fs, Bs),
sum(Bs, #=, N).
Sample query using SICStus Prolog 4.3.2:
?- count_adj_gt([1,2,3,2,1,3,2], N).
N = 3. % succeeds deterministically
not sure about
an elegant terminating condition
my whole code would be
?- Vs=[1,2,3,2,1,3,2], aggregate_all(count, (append(_,[X,Y|_], Vs), X<Y), Count).
That's all...
If you need something more complex, remember that library(clpfd) has more to offer.
I'm trying to write prolog program that sums items from two lists and present the result in another list.
For example:
List1:
[1, 3, 4, 2]
List2:
[5, 1, 3, 0]
Result:
[6, 4, 7, 2]
So far, I have this:
list_sum([],[],[]).
list_sum([H1|T1],[H2|T2],L3):-list_sum(T1,T2,[X|L3]), X is H1+H2.
?-list_sum([1,2,3,4],[1,2,3,4],R),write(R).
If you use SWI-Prolog you can use maplist, and module lambda found there : http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl :
:- use_module(library(lambda)).
list_sum(L1, L2, L3) :-
maplist(\X^Y^Z^(Z is X + Y), L1, L2, L3).
What #gusbro said. Further, you need to rearrange the order of operations and add a couple of additional special cases to deal with lists of differing lengths:
list_sum( [] , [] , [] ) .
list_sum( [] , [Y|Ys] , [Z|Zs] ) :- Z is 0+Y , list_sum( [] , Ys , Zs ) .
list_sum( [X|Xs] , [] , [Z|Zs] ) :- Z is X+0 , list_sum( Xs , [] , Zs ) .
list_sum( [X|Xs] , [Y|Ys] , [Z|Zs] ) :- Z is X+Y , list_sum( Xs , Ys , Zs ) .
You need to move the evaluation (Z is X+Y) in my example above, so that Z is evaluated before the recursion. This accomplishes two things:
First, it makes the predicate tail-recursive, meaning the solution is iterative and therefore doesn't consume stack space. In your code, the evaluations aren't performed until after the entire recursion is done. Each intermediate sum is kept on the stack and is evaluated right-to-left on your way back up. This means you'll blow your stack on a large list.
Second, evaluating each result before recursing down means you fail fast. The first sum that doesn't unify with the result fails the entire operation. Your solution fails slow. Consider 10,000,000 item lists where the first item doesn't sum to the first item in the result list: you'll traverse all 10,000,000 items, then — assuming you didn't blow your stack — you start evaluating sums right-to-left. Your predicate won't fail until the very last evalution.
it's one liner in SWI-Prolog:
list_sum(X,Y,S) :- maplist(plus, X,Y,S).
And it works also 'backward':
?- maplist(plus, [1,2,3],Y,[3,4,5]).
Y = [2, 2, 2].
You are almost there.
Your problem is that the result of the sum should be put in the head of the second clause, and not in the recursive call!
list_sum([H1|T1],[H2|T2],[X|L3]):-list_sum(T1,T2,L3), X is H1+H2.
Note that the way you had written it, L3 which is "returned" in as a result is a list in which you have removed the head (X) from the recusive call; whereas you meant the opposite: to add an element (X) to the resulting list.
the result should be a list, so you can't just say X is H1+H2 because X is not a list and you are only matching head of the lists with a single variable. also list_sum([],[],0) is not correct for same reason. the answer looks like this:
sum([],[],[]).
sum([H1| T1], [H2| T2], [ResH| ResT]) :-
sum(T1, T2, ResT),
ResH is H1+H2.
but when you run your own code, first X is matched with H1+H2, on the second recursive call X has a value and can not be matched with head of T1+T2. so it outputs a no.
domains
list=integer*
predicates
add(list,list,list)
clauses
add([],[],[]).
add([V1X|X],[V1Y|Y],[V1Z|Z]):-add(X,Y,Z),V1Z=V1X+V1Y.