Split a list into two in prolog - list

Im trying to split a list into 2 in prolog. But im still new to this and any help would be much appreciated.
My problem is:
Implement a clause choose(N,L,R,S) that chooses N items from L and puts them in R with the remaining elements in L left in S
This is what i have tried so far:
split(0,_L1,_L2,_L4).
split(X,[H|T],L1,T):-
X>0,
X1 is X-1,
split(X1,T,[H|L1],T).
When i try to run
split(2,[1,2,4,5],X,Y).
false
This is the result i get. What am i doing wrong?

If X > 0, the first element of the L list must also be the first element of the R list. For example, this should hold: split(1, [a | Rest], [a], Rest). If we want this relationship to hold, we must express it in the head of a rule.
Your second clause should therefore look more like this:
split(X, [H|T], [H|L1], Rest) :-
X > 0,
X1 is X - 1,
split(X1, T, L1, Rest).
This splits off the prefix all right, but the rest is not right yet:
?- split(2, [1, 2, 4, 5], R, S).
R = [1, 2|S] ;
false.
You need to think again about the case where 0 elements are to be split off. What should be the result of split(0, [a, b, c], R, S)?

You biggest problem is the way in which you are constructing/deconstructing the 3rd argument.
And you're missing a special case.
Most recursive problems has a couple of special, usually terminating, cases and one general case. This problem has two special cases.
The general case is simple. You'll note here that we unify the third argument with [X|Pfx]. This adds X to the head of the left/prefix result, and gives us its (likely unbound) tail. That tail gets passed down in recursion.
partition( N , [X|Xs] , [X|Pfx] , Sfx ) :-
N > 0 ,
N1 is N-1 ,
partition( N1, Xs, Pfx, Sfx )
.
[You might notice that we're building a list in the 3rd argument (the prefix list) as we go along... but it's not a legal list: the tail is presumably unbound. We'll take care of that at the end.
So...that takes care of the general case. But, how do we know when we're done?
One special/terminating case is when the source list is exhausted. If that happens before N decrements to 0, we're done. We can handle that like this:
partition( _ , [], [], [] ).
We don't really care what the value of N is, but it might be useful to enfoce the constraint that N >= 0. What's happening here is that when the source list (the 2nd argument) is exhausted and is empty list, we (1) close the prefix list (3rd argument) and unify the suffix list with the empty list.
The next special case is when N is finally decremented to zero. That's no more complex:
partition( 0 , Sfx, [], Sfx ).
We unify whatever is left of the source list with the suffix list (4th argument) and close the prefix list with the empty list.
The remaining special case is when N is finally decremented to 0. That's just as simple. Here's:
partition( 0 , Xs, [], Xs ).
Put it all together and you get:
partition( _ , [] , [] , [] ).
partition( 0 , Sfx , [] , Sfx ).
partition( N , [X|Xs] , [X|Pfx] , Sfx ) :-
N > 0 ,
N1 is N-1,
partition( N1, Xs , Pfx , Sfx ).

Related

A prolog predicate to split a list into sperate lists ever n elements

The title is the required predicate and here are few sample queries
?- splitEvery(2,[a,b,c,d,e,f,g,h],R).
R = [[a, b], [c, d], [e, f], [g, h]] ;
false.
?- splitEvery(4,[a,b,c,d,e,f,g,h],R).
R = [[a, b, c, d], [e, f, g, h]] ;
false.
?- splitEvery(8,[a,b,c,d,e,f,g,h],R).
R = [[a, b, c, d, e, f, g, h]] ;
false.
my code so far is this
splitEvery(N,List,Res):-
splitEveryHelper1(N,List,Res,1,[]).
splitEveryHelper1(_,[],Acc,_,Acc).
splitEveryHelper1(N,[H|T],Res,C,[[H|HT]|AT]):-
C=<N,
C\_new is C+1,
splitEveryHelper1(N,T,Res,C_new,[[HT]|AT]).
splitEveryHelper1(N,List,Res,C,[AH|TR]):-
C>N,
C\_new=1,
splitEveryHelper1(N,List,Res,C_new,AT).
however it is not working properly
It helps to decompose your problem. You want to take a list of things and split it up into a individual sublists of N items, correct?
That is a matter of repeatedly doing the following:
Pulling no more than N items off the head of the list, and
Recursing down on what's left.
So, you need a predicated to pull no more than N items from the front of the list. There's 3 cases:
The general case: N > 0 and the list is non-empty. Here, we add the head of the list to the prefix that we're building, decrement N, and recurse down on what's left.
Special case #1: N > 0 and the list is empty. Here, we close the prefix and return the empty list as the suffix.
Special case #2: N is 0. Here, We close the prefix and return the source list as the suffix.
first( N , [X|L] , [X|Xs] , Sfx ) :- N > 0 , N1 is N-1 , first( N1, L, Xs, Sfx ) .
first( N , [] , [] , [] ) :- N > 0 .
first( 0 , Xs , [] , Xs ) .
Once we have that, it's an even easier matter of repeatedly invoking first/4.
If the source list is empty, then the list-of-lists is empty.
If the source list is non-empty, we
pull the first N items from the source list, and
recurse down on whatever's left over
split_every( _ , [] , [] ) .
split_every( N , [X|Xs] , [Pfx|LoL] ) :- first(N,[X|Xs],Pfx,Sfx), split_every(N,Sfx,LoL) .
You can, err... fiddle with it in this fiddle: https://swish.swi-prolog.org/p/split-list.pl
This compact fragment satisfies the queries you listed
splitEvery(N,L,R) :-
length(R,_),
maplist({N}/[X]>>length(X,N),R),
append(R,L).
but it has a big flaw (apart requiring library(yall)). Can you spot it ?
Edit
About your code: you're doing it more complex than required, and ignoring the messages the compiler gives you about singletons.
Remember that accumulators reverse the list, so you should remove them. Build instead the list in the output argument.
To give you a start:
splitEvery(N,List,Res):-
splitEveryHelper1(N,List,1,Res).
splitEveryHelper1(_,[],_,[]).
splitEveryHelper1(N,[H|T],C,[[H|R]|AT]):-
C=<N,
C_new is C+1,
....
splitEveryHelper1(N,List,C,[[]|TR]):-
C>N,
C_new=1,
....
fill the dots with the proper recursive calls. Then it will be working properly.

Prolog program that deletes every n-th element from a list

Could you help me solve the following?
Write a ternary predicate delete_nth that deletes every n-th element from a list.
Sample runs:
?‐ delete_nth([a,b,c,d,e,f],2,L).
L = [a, c, e] ;
false
?‐ delete_nth([a,b,c,d,e,f],1,L).
L = [] ;
false
?‐ delete_nth([a,b,c,d,e,f],0,L).
false
I tried this:
listnum([],0).
listnum([_|L],N) :-
listnum(L,N1),
N is N1+1.
delete_nth([],_,_).
delete_nth([X|L],C,L1) :-
listnum(L,S),
Num is S+1,
( C>0
-> Y is round(Num/C),Y=0
-> delete_nth(L,C,L1)
; delete_nth(L,C,[X|L1])
).
My slightly extravagant variant:
delete_nth(L, N, R) :-
N > 0, % Added to conform "?‐ delete_nth([a,b,c,d,e,f],0,L). false"
( N1 is N - 1, length(Begin, N1), append(Begin, [_|Rest], L) ->
delete_nth(Rest, N, RestNew), append(Begin, RestNew, R)
;
R = L
).
Let's use clpfd! For the sake of versatility and tons of other good reasons:
:- use_module(library(clpfd)).
We define delete_nth/3 based on if_/3 and (#>=)/3:
delete_nth(Xs,N,Ys) :-
N #> 0,
every_tmp_nth_deleted(Xs,0,N,Ys).
every_tmp_nth_deleted([] ,_ ,_,[] ). % internal auxiliary predicate
every_tmp_nth_deleted([X|Xs],N0,N,Ys0) :-
N1 is N0+1,
if_(N1 #>= N,
(N2 = 0, Ys0 = Ys ),
(N2 = N1, Ys0 = [X|Ys])),
every_tmp_nth_deleted(Xs,N2,N,Ys).
Sample query:
?- delete_nth([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],2,Ys).
Ys = [1,3,5,7,9,11,13,15] % succeeds deterministically
Ok, how about something a little more general?
?- delete_nth([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],N,Ys).
N = 1 , Ys = []
; N = 2 , Ys = [1, 3, 5, 7, 9, 11, 13, 15]
; N = 3 , Ys = [1,2, 4,5, 7,8, 10,11, 13,14 ]
; N = 4 , Ys = [1,2,3, 5,6,7, 9,10,11, 13,14,15]
; N = 5 , Ys = [1,2,3,4, 6,7,8,9, 11,12,13,14 ]
; N = 6 , Ys = [1,2,3,4,5, 7,8,9,10,11, 13,14,15]
; N = 7 , Ys = [1,2,3,4,5,6, 8,9,10,11,12,13, 15]
; N = 8 , Ys = [1,2,3,4,5,6,7, 9,10,11,12,13,14,15]
; N = 9 , Ys = [1,2,3,4,5,6,7,8, 10,11,12,13,14,15]
; N = 10 , Ys = [1,2,3,4,5,6,7,8,9, 11,12,13,14,15]
; N = 11 , Ys = [1,2,3,4,5,6,7,8,9,10, 12,13,14,15]
; N = 12 , Ys = [1,2,3,4,5,6,7,8,9,10,11, 13,14,15]
; N = 13 , Ys = [1,2,3,4,5,6,7,8,9,10,11,12, 14,15]
; N = 14 , Ys = [1,2,3,4,5,6,7,8,9,10,11,12,13, 15]
; N = 15 , Ys = [1,2,3,4,5,6,7,8,9,10,11,12,13,14 ]
; N in 16..sup, Ys = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15].
Please follow aBathologist instructive answer and explanation (+1). I just post my own bet at solution since there is a problem in ditto solution for ?‐ delete_nth([a,b,c,d,e,f],0,L)..
delete_nth(L,C,R) :-
delete_nth(L,C,1,R).
delete_nth([],_,_,[]).
delete_nth([_|T],C,C,T1) :- !, delete_nth(T,C,1,T1).
delete_nth([H|T],N,C,[H|T1]) :- C<N, C1 is C+1, delete_nth(T,N,C1,T1).
yields
1 ?- delete_nth([a,b,c,d,e,f],2,L).
L = [a, c, e].
2 ?- delete_nth([a,b,c,d,e,f],1,L).
L = [].
3 ?- delete_nth([a,b,c,d,e,f],0,L).
false.
A minor (?) problem: this code is deterministic, while the samples posted apparently are not (you have to input ';' to get a false at end). Removing the cut will yield the same behaviour.
An interesting - imho - one liner variant:
delete_nth(L,C,R) :- findall(E, (nth1(I,L,E),I mod C =\= 0), R).
but the C==0 must be ruled out, to avoid
ERROR: mod/2: Arithmetic: evaluation error: `zero_divisor'
Edited, correcting the mistake pointed out by #CapelliC, where predicate would succeed on N = 0.
I can see where you're headed with your solution, but you needn't bother with so much arithmetic in this case. We can delete the Nth element by counting down from N repeatedly until the list is empty. First, a quick note about style:
If you use spaces, line breaks, and proper placement of parenthesis you can help your readers parse your code. Your last clause is much more readable in this form:
delete_nth([X|L], C, L1):-
listnum(L, S),
Num is S+1,
C>0 -> Y is round(Num/C),
Y=0 -> delete_nth(L, C, L1)
; delete_nth(L, C, [X|L1]).
Viewing your code now, I'm not sure whether you meant to write
( C>0 -> ( Y is round(Num/C),
Y=0 -> delete_nth(L, C, L1) )
; delete_nth(L, C, [X|L1])
).
or if you meant
C>0 -> Y is round(Num/C),
( Y=0 -> delete_nth(L, C, L1)
; delete_nth(L, C, [X|L1])
).
or perhaps you're missing a ; before the second conditional? In any case, I suggest another approach...
This looks like a job for auxiliary predicates!
Often, we only need a simple relationship in order to pose a query, but the computational process necessary to resolve the query and arrive at an answer calls for a more complex relation. These are cases where it is "easier said than done".
My solution to this problem works as follows: In order to delete every nth element, we start at N and count down to 1. Each time we decrement the value from N, we move an element from the original list to the list of elements we're keeping. When we arrive at 1, we discard the element from our original list, and start counting down from N again. As you can see, in order to ask the question "What is the list Kept resulting from dropping every Nth element of List?" we only need three variables. But my answer the question, also requires another variable to track the count-down from N to 1, because each time we take the head off of List, we need to ask "What is the Count?" and once we've reached 1, we need to be able to remember the original value of N.
Thus, the solution I offer relies on an auxiliary, 4-place predicate to do the computation, with a 3-place predicate as the "front end", i.e., as the predicate used for posing the question.
delete_nth(List, N, Kept) :-
N > 0, %% Will fail if N < 0.
delete_nth(List, N, N, Kept), !. %% The first N will be our our counter, the second our target value. I cut because there's only one way to generate `Kept` and we don't need alternate solutions.
delete_nth([], _, _, []). %% An empty list has nothing to delete.
delete_nth([_|Xs], 1, N, Kept) :- %% When counter reaches 1, the head is discarded.
delete_nth(Xs, N, N, Kept). %% Reset the counter to N.
delete_nth([X|Xs], Counter, N, [X|Kept]) :- %% Keep X if counter is still counting down.
NextCount is Counter - 1, %% Decrement the counter.
delete_nth(Xs, NextCount, N, Kept). %% Keep deleting elements from Xs...
Yet another approach, following up on #user3598120 initial impulse to calculate the undesirable Nth elements away and inspired by #Sergey Dymchenko playfulness. It uses exclude/3 to remove all elements at a 1-based index that is multiple of N
delete_nth(List, N, Kept) :-
N > 0,
exclude(index_multiple_of(N, List), List, Kept).
index_multiple_of(N, List, Element) :-
nth1(Index, List, Element),
0 is Index mod N.

Friendly lists prolog

I am given 2 lists for example K=[a,b,c,d,e,f,g] and L=[a,b,1,d,e,2,g]. When these 2 lists have 2 different elements, then they are friendly.
This is what I've tried:
friendly(K,L):-
append(L1,[Z],A1),
append(A1,L2,A2),
append(A2,[Q],A3),
append(A3,L3,K),
append(L1,[Y],B1),
append(B1,L2,B2),
append(B2,[W],B3),
append(B3,L3,L),
Z\=Y,
Q\=W.
Thank you all so much, at last I found the correct code:
friend(L1,L2):-
append(A,Y,L1),
append([Z|T],[F|TT],Y),
append(A,Q,L2),
append([R|T],[O|TT],Q),
Z\=R,
F\=O.
You can use append/3 in this way to locate the first different elements.
first_different(L1,L2, R1,R2) :-
append(H, [E1|R1], L1),
append(H, [E2|R2], L2),
E1 \= E2.
H is the common part, R1,R2 are the 'remainders'. This code is more in line with your second comment above.
Now you must apply two times this helper predicate, and the second time also 'remainders' must be equal, or one of them must be empty. That is
friendly(L1,L2) :-
first_different(L1,L2,R1,R2),
first_different(R1,R2,T1,T2),
once((T1=T2;T1=[];T2=[])).
Alternatively, using some builtin can be rewarding. This should work
friendly(L1,L2) :- findall(_,(nth1(I,L1,E1),nth1(I,L2,E2),E1\=E2),[_,_]).
Wouldn't it be better to do something like the following?
diff([], [], []).
diff([], K, K).
diff(L, [], L).
diff([H | TL], [H | TK], D) :- diff(TL, TK, D),!.
diff([HL | TL], [HK | TK], [HL, HK | D]) :- diff(TL, TK, D),!.
friendly(K, L) :- diff(K, L, D), length(D, Length), Length < 3.
But your problem really is underspecified. For example my program really cares about order so [a,x,b] and [a,b] are not friendly by my definition.
I'm still a little uncertain about the total definition of "friendly" list, but I think this might answer it:
friendly(A, B) :-
friendly(A, B, 2).
friendly([H|TA], [H|TB], C) :-
C > 0,
friendly(TA, TB, C).
friendly([HA|TA], [HB|TB], C) :-
HA \= HB,
C > 0,
C1 is C-1,
friendly(TA, TB, C1).
friendly(A, [], C) :-
length(A, L),
L =< C.
friendly([], B, C) :-
length(B, L),
L =< C.
friendly(A, A, 0).
I'm assuming that the definition of friendly means the lists are in "lock step" outside of the maximum of two differences.
Does order matter? Are the lists sets (each element is unique) or bags (duplicates allowed)?
Assuming that
Order doesn't matter ([1,2,3] and [1,3,2]) are treated as identical), and
Duplicates don't matter ([1,2,3,1] and [1,2,3]) are treated as identical
Something like this might be along the lines of what you're looking for:
friendly(Xs,Ys) :-
set_of(
E ,
(
( member(E,Xs) ,
not( member(E,Ys) )
)
;
(
member(E,Ys) ,
not( member(E,Xs) )
) ,
Zs
) ,
length( Zs , L ) ,
L =< 2
.
Find the set of all elements of each list that aren't in the other and succeed if the resulting list is of length 0, 1 or 2.
I came up with something similar to others.. I just keep a list of '_' items (final param of diff_list) - one for each difference, be that a value difference at the same index, or a difference in the length, then finally in friendly/2, check that has 2 items.
% recursion base
diff_list([], [], []).
% the head of both lists are the same, don't add to diff list
diff_list([HK|TK], [HK|TL], Diff) :-
diff_list(TK, TL, Diff).
% the above rule failed, so must be a difference, add a '_'
diff_list([_|TK], [_|TL], [_|Diff]) :-
diff_list(TK, TL, Diff).
% 1st list is empty, but the 2nd isn't. That's a diff again.
diff_list([], [_|TL], [_|Diff]) :-
diff_list([], TL, Diff).
% 2nd list is empty, but the 1st isn't. Another diff.
diff_list([_|TK], [], [_|Diff]) :-
diff_list(TK, [], Diff).
% friendly is true if the diff list length unifies with 2 item length list [_,_]
friendly(K, L) :-
diff_list(K, L, [_,_]).

Count only numbers in list of numbers and letters

I'm new to Prolog and I can't seem to get the answer to this on my own.
What I want is, that Prolog counts ever Number in a list, NOT every element. So for example:
getnumbers([1, 2, c, h, 4], X).
Should give me:
X=3
getnumbers([], 0).
getnumbers([_ | T], N) :- getnumbers(T, N1), N is N1+1.
Is what I've got, but it obviously gives me every element in a list. I don't know how and where to put a "only count numbers".
As usual, when you work with lists (and SWI-Prolog), you can use module lambda.pl found there : http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl
:- use_module(library(lambda)).
getnumbers(L, N) :-
foldl(\X^Y^Z^(number(X)
-> Z is Y+1
; Z = Y),
L, 0, N).
Consider using the built-in predicates (for example in SWI-Prolog), and checking their implementations if you are interested in how to do it yourself:
include(number, List, Ns), length(Ns, N)
Stay logically pure, it's easy: Use the meta-predicate
tcount/3 in tandem with the reified type test predicate number_t/2 (short for number_truth/2):
number_t(X,Truth) :- number(X), !, Truth = true.
number_t(X,Truth) :- nonvar(X), !, Truth = false.
number_t(X,true) :- freeze(X, number(X)).
number_t(X,false) :- freeze(X,\+number(X)).
Let's run the query the OP suggested:
?- tcount(number_t,[1,2,c,h,4],N).
N = 3. % succeeds deterministically
Note that this is monotone: delaying variable binding is always logically sound. Consider:
?- tcount(number_t,[A,B,C,D,E],N), A=1, B=2, C=c, D=h, E=4.
N = 3, A = 1, B = 2, C = c, D = h, E = 4 ; % succeeds, but leaves choice point
false.
At last, let us peek at some of the answers of the following quite general query:
?- tcount(number_t,[A,B,C],N).
N = 3, freeze(A, number(A)), freeze(B, number(B)), freeze(C, number(C)) ;
N = 2, freeze(A, number(A)), freeze(B, number(B)), freeze(C,\+number(C)) ;
N = 2, freeze(A, number(A)), freeze(B,\+number(B)), freeze(C, number(C)) ;
N = 1, freeze(A, number(A)), freeze(B,\+number(B)), freeze(C,\+number(C)) ;
N = 2, freeze(A,\+number(A)), freeze(B, number(B)), freeze(C, number(C)) ;
N = 1, freeze(A,\+number(A)), freeze(B, number(B)), freeze(C,\+number(C)) ;
N = 1, freeze(A,\+number(A)), freeze(B,\+number(B)), freeze(C, number(C)) ;
N = 0, freeze(A,\+number(A)), freeze(B,\+number(B)), freeze(C,\+number(C)).
of course, you must check the type of an element to see if it satisfies the condition.
number/1 it's the predicate you're looking for.
See also if/then/else construct, to use in the recursive clause.
This uses Prolog's natural pattern matching with number/1, and an additional clause (3 below) to handle cases that are not numbers.
% 1 - base recursion
getnumbers([], 0).
% 2 - will pass ONLY if H is a number
getnumbers([H | T], N) :-
number(H),
getnumbers(T, N1),
N is N1+1.
% 3 - if got here, H CANNOT be a number, ignore head, N is unchanged, recurse tail
getnumbers([_ | T], N) :-
getnumbers(T, N).
A common prolog idiom with this sort of problem is to first define your predicate for public consumption, and have it invoke a 'worker' predicate. Often it will use some sort of accumulator. For your problem, the public consumption predicate is something like:
count_numbers( Xs , N ) :-
count_numbers_in_list( Xs , 0 , N ) .
count_numbers_in_list( [] , N , N ) .
count_numbers_in_list( [X|Xs] , T , N ) :-
number(X) ,
T1 is T+1 ,
count_numbers_in_list( Xs , T1 , N )
.
You'll want to structure the recursive bit so that it is tail recursive as well, meaning that the recursive call depends on nothing but data in the argument list. This allows the compiler to reuse the existing stack frame on each call, so the predicate becomes, in effect, iterative instead of recursive. A properly tail-recursive predicate can process a list of infinite length; one that is not will allocate a new stack frame on every recursion and eventually blow its stack. The above count_numbers_in_list/3 is tail recursive. This is not:
getnumbers([H | T], N) :-
number(H),
getnumbers(T, N1),
N is N1+1.

Prolog - summing numbers from two lists

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.