Given a list of positive integer Items whose elements are guaranteed to be in sorted ascending order, and a positive integer Goal, and Output is a list of three elements [A,B,C] taken from items that together add up to goal. The Output must occur inside the items list in that order (ascending order).
ex:
?- threeSum([3,8,9,10,12,14],27,Output).
Output=[8,9,10];
Output=[3,10,14].
someone helped me to reach this to this code
but it gives me singleton variables:[Input,Items] ,it didnt work
although iam not quite sure if this is a greedy algorithm search or not ?
threeSum(Input,Goal,[A,B,C]):-
permutation(Items, [A,B,C|Rest]),
msort([A,B,C],[A,B,C]),
msort(Rest,Rest),
sum_list([A,B,C],Goal).
A clpfd approach:
:- use_module(library(clpfd)).
threeSum(Input, Goal, [A,B,C]) :-
Input = [First|Rest],
foldl([N,M,T]>>(T = N\/M), Rest, First, Domain),
[A,B,C] ins Domain,
all_different([A,B,C]),
chain([A,B,C], #>=),
Goal #= A + B + C,
labeling([max(A), max(B), max(C)], [A,B,C]).
Which has a bit of wrangling to turn the list of numbers into a domain, then says [A,B,C] must be in the list of numbers, must be different numbers, must be in descending order, must sum to the goal, and the clpfd solver should strive to maximise the values of A then B then C. (This probably won't work if the list can contain multiple of the same value like [5,5,5,3,2]).
e.g.
?- threeSum([3,8,9,10,12,14], 27, Output).
Output = [14, 10, 3] ;
Output = [10, 9, 8]
nums_goal_answer(Input, Goal, [A,B,C]) :-
length(Input, InputLen),
reverse(Input, RInput), % 'greedy' interpreted as 'prefer larger values first'.
% and larger values are at the end.
between( 1, InputLen, N1),
between(N1, InputLen, N2), % three nested for-loops equivalent.
between(N2, InputLen, N3),
\+ N1 = N2, % can't pick the same thing more than once.
\+ N2 = N3,
nth1(N1, RInput, A, _),
nth1(N2, RInput, B, _),
nth1(N3, RInput, C, _),
sum_list([A,B,C], Goal).
someone helped me to reach this to this code but it gives me singleton variables:[Input,Items], it didnt work
The warning is because the code never looks at the numbers in the Input list. Without doing that, how could it ever work?
although iam not quite sure if this is a greedy algorithm
is it taking the biggest things first? I don't think permutation will do that.
Using DCG:
:- use_module(library(dcg/basics)).
three_sum_as_dcg(Total, Lst, LstThree) :-
phrase(three_sum_dcg(3, Total), Lst, LstThree).
% When finished, remove the remainder, rather than add to LstThree
three_sum_dcg(0, 0) --> remainder(_).
three_sum_dcg(NumsLeft, Total), [N] -->
% Use this element
[N],
{ three_sum_informed_search(NumsLeft, Total, N),
succ(NumsLeft0, NumsLeft),
Total0 is Total - N
},
three_sum_dcg(NumsLeft0, Total0).
three_sum_dcg(NumsLeft, Total) -->
% Skip this element
[N],
{ three_sum_informed_search(NumsLeft, Total, N) },
three_sum_dcg(NumsLeft, Total).
three_sum_informed_search(NumsLeft, Total, N) :-
NumsLeft > 0,
% "Informed" search calc due to list nums not decreasing
Total >= (N * NumsLeft).
Result in swi-prolog (note the efficiency):
?- numlist(1, 1000000, L), time(findall(L3, three_sum_as_dcg(12, L, L3), L3s)).
% 546 inferences, 0.000 CPU in 0.000 seconds (97% CPU, 4740036 Lips)
L3s = [[1,2,9],[1,3,8],[1,4,7],[1,5,6],[2,3,7],[2,4,6],[3,4,5]].
Restating the problem statement:
Given that I have
A [source] list of positive integers, whose elements are guaranteed to be sorted in ascending order, and
a positive integer indicating the target value.
I want to find
an ordered subset of elements of the source list that sum to the target value
The simplest way is often the easiest (and the most general):
sum_of( _ , 0 , [] ) . % nothing adds up to nothing.
sum_of( [X|Xs] , S , [X|Ys] ) :- % otherwise...
S > 0 , % - if the target sum S is positive,
X =< S , % - and the head of the list is less than or equal to the target sum
S1 is S-X , % - remove that amount from the target sum, and
sum_of(Xs,S1,Ys) . % - recurse down with the new target sum
sum_of( [_|Xs] , S , Ys ) :- % then, on backtracking...
S > 0 , % - assuming that the target sum is positive,
sum_of(Xs,S,Ys). % - recurse down again, discarding the head of the list
This will find whatever combinations of however many list elements sum to the target value. It will find them from left to right, so
sum_of( [1,2,3,4,5,6,7,8,9], 10, L ).
will, on backtracking successively find
L = [ 1, 2, 3, 4 ]
L = [ 1, 2, 7 ]
L = [ 1, 3, 6 ]
L = [ 1, 4, 5 ]
L = [ 1, 9 ]
L = [ 2, 3, 5 ]
L = [ 2, 8 ]
L = [ 3, 7 ]
L = [ 4, 6 ]
If you want to change the order so it finds the largest values first, simply reverse the order of clauses 2 and 3 in sum_of/3:
sum_of( _ , 0 , [] ) .
sum_of( [_|Xs] , S , Ys ) :-
S > 0 ,
sum_of(Xs,S,Ys) .
sum_of( [X|Xs] , S , [X|Ys] ) :-
S > 0 ,
X =< S ,
S1 is S-X ,
sum_of(Xs,S1,Ys) .
Now it will return the same set of solutions, just in the reverse order, starting with [4,6] and finishing with [1,2,3,4].
Once you have solved the general problem, it's a simple matter of restricting it to a specified number of elements, for instance:
sum_of_n_elements(Xs,N,S,Ys) :- length(Ys,N), sum_of(Xs,S,Ys).
And to get just the 3-element subsets that sum to the target value:
sum_of_3_elements(Xs,S,Ys) :- sum_of_n_elements(Xs,3,S,Ys) .
https://swish.swi-prolog.org/p/XKjdstla.pl
Related
This recursion should slice IL to IR out of the list Lin and hand result LOut...
slice(_,IL,IR,LOut) :-
IR<IL,
[LOut].
slice(Lin,IL,IR,LOut) :-
nth0(IL,Lin,X),
append(LOut,[X],LOut2),
IK is IL + 1,
slice(Lin,IK,IR,LOut2).
Input / Output:
?- slice([1,2,3,4],2,3,X).
ERROR: source_sink `'3'' does not exist
ERROR: source_sink `'4'' does not exist
X = [] .
I m also new to Prolog, but I think this recursion must somehow work. Also I'm not really known to the error codes in Prolog, but after checking multiple times I just have to give up... I hope you guys can help me.
slice(_,IL,IR,LOut) :-
IR<IL,
[LOut]. % <-- this line causes source_sink error.
That syntax [name] tries to load the file name.pl as Prolog source code. By the time your code gets there, LOut is [3,4] so it tries to load the files 3.pl and 4.pl, and they don't exist (thankfully, or else who knows what they could do).
I think this recursion must somehow work
It won't; you are appending to a list as you go down into the recursion, which means you will never see the result.
The following might be a close version which works, at least one way:
slice(_,IL,IR,[]) :-
IR < IL.
slice(Lin,IL,IR,[X|LOut]) :-
IR >= IL,
nth0(IL,Lin,X),
IK is IL + 1,
slice(Lin,IK,IR,LOut).
?- slice([0,1,2,3,4,5,6,7,8,9], 2, 5, X).
X = [2, 3, 4, 5]
See how [X|LOut] in the second rule's header puts X in the result that you get, and append/3 is not needed, and LOut finishes down in the recursion eventually as [] the empty list from the first rule, and all the X's are prepended on the front of it to make the result on the way down into the recursion, which is tail recursion, so it doesn't need to go back up, only forward, since there's nothing left to be done after the recursive call.
Since the "cons" is done before the recursion, this is known as "tail recursion modulo cons" in other languages, but in Prolog it is just tail, and the list is being built top-down on the way forward, as opposed to being built bottom up on the way back:
Lin=[0,1,2,3,4,5,6,7,8,9], slice( Lin, 2, 5, R)
:-
nth0(2,Lin,X2), R=[X2|R2], slice( Lin, 3, 5, R2)
:-
nth0(3,Lin,X3), R2=[X3|R3], slice( Lin, 4, 5, R3)
:-
nth0(4,Lin,X4), R3=[X4|R4], slice( Lin, 5, 5, R4)
:-
nth0(5,Lin,X5), R4=[X5|R5], slice( Lin, 6, 5, R5)
:-
R5 = [].
I think findall/3 provides a readable readable solution for your problem:
slice(Lin,IL,IR,LOut) :-
findall(E,(nth0(P,Lin,E),between(IL,IR,P)),LOut).
yields
?- slice([1,2,3,4],2,3,X).
X = [3, 4].
If you expect a different outcome, use standard arithmetic comparison operators (=<,>=) instead of between/3.
I think you want:
list_elems_slice(Start, End, Lst, Slice) :-
list_elems_slice_(Lst, 1, Start, End, Slice).
list_elems_slice_([H|T], N, N, End, [H|Slice]) :-
list_elems_slice_capture_(T, N, End, Slice).
list_elems_slice_([_|T], N, Start, End, Slice) :-
N1 is N + 1,
list_elems_slice_(T, N1, Start, End, Slice).
list_elems_slice_capture_(_, N, N, []).
list_elems_slice_capture_([H|T], N, End, [H|Slice]) :-
N1 is N + 1,
list_elems_slice_capture_(T, N1, End, Slice).
Result in swi-prolog:
?- list_elems_slice(S, E, [a,b,c], Slice).
S = E, E = 1,
Slice = [a] ;
S = 1,
E = 2,
Slice = [a, b] ;
S = 1,
E = 3,
Slice = [a, b, c] ;
S = E, E = 2,
Slice = [b] ;
S = 2,
E = 3,
Slice = [b, c] ;
S = E, E = 3,
Slice = [c] ;
false.
Assuming that the point of this exercise is to teach you to think recursively, I would approach the problem as follows.
To get what you want is essentially two separate operations:
You first must discard some number of items from the beginning of the list, and then
Take some number of items from what's left over
That gives us discard/3:
discard( Xs , 0 , Xs ) .
discard( [_|Xs] , N , Ys ) :- N > 0 , N1 is N-1, discard(Xs,N1,Ys) .
and take/3, very nearly the same operation:
take( _ , 0 , [] ) .
take( [X|Xs] , N , [Y|Ys] ) :- N > 0 , N1 is N-1, take(Xs,N1,Ys) .
Once you have those two simple predicates, slice/4 itself is pretty trivial:
%
% slice( List , Left, Right, Sublist )
%
slice( Xs, L, R, Ys ) :- % to slice a list,
L =< R, % - the left offset must first be less than or equal to the right offset
N is R-L, % - compute the number of items required, and then
discard(Xs,L,X1), % - discard the first L items, and
take(X1,N,Ys). % - take the next N items
. % Easy!
Another approach would be to use append/3:
slice( Xs , L, R, Ys ) :-
length(Pfx,L), % - construct of list of the length to be discarded
append(Pfx,Sfx,Xs), % - use append to split Xs
N is R-L, % - compute the number of items required
length(Ys,N), % - ensure Ys is the required length
append(Ys,_,Sfx) % - use append to split off Ys
. % Easy!
`three Sum([1,2,3,4,5,6,7,8,9],12,Output).
Output=[1,2,9];
Output=[1,3,8];
Output=[1,4,7];
Output=[1,5,6];
Output=[2,3,7];
Output=[2,4,6];
Output=[3,4,5]`
we should make result = summation 3 elements sorted ascendingly from list
This is fundamentally a matter of finding all the combinations of n things taken k at a time. To do that is pretty simple:
combination( 0 , _ , [] ) :- !.
combination( N , L , [C|Cs] ) :-
N > 0,
N1 is N-1,
select(L,C,L1),
combination(N1, L1, Cs).
select( [H|T] , H, T ) .
select( [_|T] , H, R ) :- select(T,H,R) .
once you have that, then it is a matter of wrapping it up nicely:
combination_sum( Xs, K, V, Ys ) :-
sort(Xs,X0), % orders the list, making it a proper set by removing duplicates
length(Xs,L),
between(1,L,K), % ensures K has a sensible value (and allows K to be unbound
combination(K,X0,Ys),
sum_of(Ys,V).
sum_of( Xs , S ) :- sum_of(Xs,0,S).
sum_of( [] , S , S ).
sum_of( [X|Xs] , T , S ) :- T1 is T+X, sum_of(Xs,T1,S) .
That gives you the generic, flexible solution: you can solve the problem for any given sized subset.
Note also that you may, should you choose, leave K or V unbound (or both, for that matter), and it will return all solutions for the given constraints:
combination_sum( [1..n], K, V, L ) yields all combinations of any length and their sum
combination_sum( [1..n], K, 12, L ) yields all combinations of any length that sum to 12.
combination_sum( [1..n], 3, V, L ) yields all combinations of length 3 that sum to any value.
combination_sum( [1...n], 3, 12, L ) yields all combinations of length 3 that sum to 12.
Then, just wrap that for your specialized use case:
sum_three(Xs,V,Ys) :- combination_sum(Xs,3,V,Ys).
three_sum(Lst, Total, [One, Two, Three]) :-
% Using msort, to sort without removing duplicates
msort(Lst, LstSorted),
select_remainder(One, LstSorted, Lst1),
select_remainder(Two, Lst1, Lst2),
select_remainder(Three, Lst2, _),
Total is One + Two + Three.
select_remainder(Elem, [H|T], RemainderForward) :-
select_remainder_(T, H, Elem, RemainderForward).
select_remainder_(T, H, H, T).
select_remainder_([H|T], _, Elem, R) :-
select_remainder_(T, H, Elem, R).
Result in swi-prolog:
?- time(findall(Lst, three_sum([1,2,3,4,5,6,7,8,9], 12, Lst), Lsts)).
% 278 inferences, 0.000 CPU in 0.000 seconds (93% CPU, 1220471 Lips)
Lsts = [[1,2,9],[1,3,8],[1,4,7],[1,5,6],[2,3,7],[2,4,6],[3,4,5]].
I need to multiply and sum one list, the output should be like this:
?- tp4([1,7,0,1,2,3,5], L).
L = [210,19,1,7,0,1,2,3,5]
First the multi, next the sum and at the end the rest of the numbers.
Here is a builing brick answer to your question since you seem to have a "where to start" problem. It is important to learn it by yourself, therefore you can conclude the correct answer by using maplist/2 and fold/4 as mentioned from David Tonhofer. But these are "advanced" predicates, so lets start from scratch and implement the base functionalities.
First: how to append elements to a list. You can either put something as a head of a list ([Head|List]) or use the predicate append/2 (which is build in but you can easily implement it by yourself). Note that variables start with a capital letter.
?- List=[1,2,3,4], Head = 0, Out=[Head|List].
Head = 0,
List = [1, 2, 3, 4],
Out = [0, 1, 2, 3, 4].
?- List2=[1,2,3,4], List1 = [0], append(List1,List2,Out).
List1 = [0],
List2 = [1, 2, 3, 4],
Out = [0, 1, 2, 3, 4].
You are be able to add elements to a list.
If you want to implement your own predicate, which works on lists, you either use the inbuild predicates or implement it yourself. We'll do the second one for the example of subtraction (all elements are subtracted from the last element).
Our predicate subtract/2 needs 2 attributes: a list (input) and a "return" value (output).
If the list has only one element ([H]), return the element. Otherwise split the list into a Head element and a Rest list ([Head|Rest]), compute the substract value for the list Rest (Tmp) and subtract Head from it:
subtract([H],[H]).
subtract([Head|Rest], Sub):-
subtract(Rest,Tmp),
Sub is Tmp - Head.
Test:
?- subtract([1,2,3,10],O).
O = 4 ;
false.
Works, not perfect but works. Now you know how to add elements to a list and have an example how to build predicated which operate on lists and use arithemtic functions. Now you can build your desired function.
You need to walk the list and compute the product and sum as you go from element to element. Given the neutral elements of the product and sum are, respectively, 1 and 0:
product_sum_list([Head| Tail], [Product, Sum, Head| Tail]) :-
product_sum_list(Tail, Head, 1, Product, 0, Sum).
Note that we're requiring the list to have at least one element. The auxiliary product_sum_list/6 performs the actual computation of the product and sum:
product_sum_list([], Last, Product0, Product, Sum0, Sum) :-
Product is Product0 * Last,
Sum is Sum0 + Last.
product_sum_list([Next| Tail], Current, Product0, Product, Sum0, Sum) :-
Product1 is Product0 * Current,
Sum1 is Sum0 + Current,
product_sum_list(Tail, Next, Product1, Product, Sum1, Sum).
By splitting the list between its head tail moving the tail to the first argument of the auxiliary predicate, we take advantage of the first argument indexing provided by the generality of Prolog systems to avoid the creation of spurious choice-points.
Sample call:
| ?- product_sum_list([1,7,0,1,2,3,5], L).
L = [0,19,1,7,0,1,2,3,5]
yes
You can achieve the same results using, as David suggested, meta-predicates for mapping and folding lists. But given that we need to compute both product and sum, the straight-forward solution is simpler and more efficient.
A common Prolog idiom is the use of a helper predicate, that takes extra arguments that maintain state. These also help you get to tail recursion so as to not consume stack.
The naive way to multiply a list might be:
multiply( [] , 0 ) . % The empty list has a product of zero.
multiply( [P] , P ) . % A list of length 1 is the value of the singleton element.
multiply( [N|Ns] , P ) :- % To compute the product of a list of length > 1...
multiply(Ns,T), % - recursively multiply the tail of the list, then
P is N * T % - multiply the head by the product of the tail
. % Easy!
Summation would be pretty much identical save for the operation involved.
[Note: given a list of sufficient length, this would eventually fail due to a stack overflow.]
Using a helper predicate (1) makes it tail recursive, meaning it won't blow up and die on a long list, and (2) will facilitate combining summation and multiplication. The 'helper' implementation looks like this:
multiply( [] , 0 ) .
multiply( [N|Ns] , P ) :- multiply(Ns,N,P).
multiply( [] , P , P ) .
multiply( [N|Ns] , T , P ) :-
T1 is T * N ,
multiply( Ns, T1, P )
.
And summation, again, is pretty much identical.
Now we can combine them to get what you want:
multiply_and_sum( [] , [0,0] ) .
multiply_and_sum( [N|Ns] , [P,S|Ns] ) :-
multiply_and_sum( Ns, N, N, P, S )
.
multiply_and_sum( [] , P, S, P, S ) .
multiply_and_sum( [N|Ns] , X, Y, P, S ) :-
X1 is X * N,
Y1 is Y + N,
multiply_and_sum( Ns, X1, Y1, P , S )
.
I am trying to figure out how sort/2 is implemented in Prolog. I would like to see how it works but I cannot find the code for it anywhere. Does somebody know how it is implemented?
In SWI-Prolog, sort/2 is a "built-in", so it's in C.
The file seems to be src/pl-lists.c of the distribution.
Here it is:
https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-list.c
At line 543:
static
PRED_IMPL("sort", 2, sort, PL_FA_ISO)
{ PRED_LD
return pl_nat_sort(A1, A2,
TRUE, SORT_ASC,
0, NULL, FALSE PASS_LD);
}
pl_nat_sort is in the same file
The comment is historically interesting:
Natural merge sort. Code contributed by Richard O'Keefe and integrated
into SWI-Prolog by Jan Wielemaker. The nice point about this code is
that it uses no extra space and is pretty stable in performance.
Richards claim it that many qsort() implementations in libc are very
slow. This isn't the case for glibc 2.2, where this performs about the
same as the previous qsort() based implementation.
Presumably Richard O'Keefe notes:
I've been using a variant of this code in a sorting utility since about
1988. It leaves the UNIX sort(1) program in the dust. As you may know,
sort(1) breaks the input into blocks that fit in memory, sorts the
blocks using qsort(), and writes the blocks out to disc, then merges the
blocks. For files that fit into memory, the variant of this code runs
about twice as fast as sort(1). Part of that is better I/O, but part is
just plain not using qsort().
Dayum. That brings back memories of writing sorting algorithms in '89.
If you just are seaching for any sorting algorithm you can always use bubblesort *cough*. It is one of the most simple and inefficient ways to sort a list, but - depending on the implementation - will run through an already sorted list in linear time. Bubblesort does not remove duplicates. This implementation does descending order:
bubblesort(List, SortedList) :-
bubbleit(List, List1),
! ,
bubblesort(List1, SortedList) .
bubblesort(List, List).
bubbleit([X,Y|Rest], [Y,X|Rest]) :-
X < Y,
! .
bubbleit([Z|Rest], [Z|Rest1]) :-
bubbleit(Rest, Rest1).
?- bubblesort([1,2,5,4,7,3,2,4,1,5,3],L).
L = [7, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1].
If you want to sort for the second element in a list [_,E|] change the the first bubbleit rule to
bubbleit([X,Y|Rest], [Y,X|Rest]) :-
X = [_,XX|_],
Y = [_,YY|_],
XX < YY,
! .
?- bubblesort([[a,3],[b,5],[c,1],[d,4]],L).
L = [[b, 5], [d, 4], [a, 3], [c, 1]].
Try searching quicksort.
Here is one link: https://www.codepoc.io/blog/prolog/4934/prolog-program-to-sort-a-list-using-quick-sort
Here is another example:-
quicksort([], []).
quicksort([X | Tail], Sorted):-
split(X, Tail, Small, Big),
quicksort(Small, SortedSmall),
quicksort(Big, SortedBig),
concatenate(SortedSmall, [X| SortedBig], Sorted).
split(X, [], [], []).
split(X, [Y| Tail], [Y | Small], Big):-
X > Y, !,
split(X, Tail, Small, Big).
split(X, [Y| Tail], Small, [Y | Big]):-
split(X, Tail, Small, Big).
concatenate([],List,List).
concatenate([Item|List1],List2,[Item|List3]) :-
concatenate(List1,List2,List3).
?-quicksort([1,7,4,3,6,5,9,8,12,1],L).
L = [1, 1, 3, 4, 5, 6, 7, 8, 9, 12]
false
The merge sort algorithm is a natural fit for Prolog. Not to mention trivial to implement in a language with recursion and lists as fundamental.
Here's a SWI Playground: https://swish.swi-prolog.org/p/swi-prolog-merge-sort.pl
merge_sort( [], [] ). % The empty list is by definition ordered
merge_sort( [X], [X] ). % So is a list of length one
merge_sort( Unsorted, Sorted ) :- % otherwise...
partition( Unsorted, L, R ) , % partition the list into 2 halves
merge_sort(L,L1), % recursively sort the left half
merge_sort(R,R1), % recursively sort the right half
merge(L1,R1,Sorted) % merge the newly-sorted halves
. % See? simple!
partition( [] , [] , [] ). % the empty list gets partitioned into two empty lists
partition( [X] , [X] , [] ). % a left of length 1 gets partitioned into itself and an empty list
partition( [X,Y|L] , [X|Xs] , [Y|Ys] ) :- % list of length 2 or more gets popped and divided between left and right halves
partition(L,Xs,Ys) % with the remainder being recursively partitioned.
. % Easy!
merge( [] , [] , [] ). % merging to empty lists is trivial
merge( [] , [Y|Ys] , [Y|Ys] ). % merging an empty list and a non-empty list is easy
merge( [X|Xs] , [] , [X|Xs] ). % merging a non-empty list and an empty list is easy
merge( [X|Xs] , [Y|Ys] , [Lo,Hi|Zs] ) :- % otherwise...
compare(X,Y,Lo,Hi), % compare the two terms, put them in collating sequence
merge(Xs,Ys,Zs) % and recursively merge the tails
. % Easy!
compare( X , Y , X, Y ) :- X #=< Y. % if X <= Y, X is Lo, and Y is Hi
compare( X , Y , Y, X ) :- X #> Y. % if X > Y, Y is Lo, and X is Hi
i am a begginer in prolog and i want to write a code that creates a list based on another list.I wrote this :
create([_],N,J,K,J):- N>K.
create([X|Xs],N,L,K,J):- X==N , N1 is N + 1 , create(Xs,N1,[-1|L],K,J).
create([X|Xs],N,L,K,J):-N1 is N + 1 , create([X|Xs],N1,[0|L],K,J).
K is the size of the output list.
N is a counter .
L is the output.
X is the input list.
?- create([1,2],1,[],5,N).
N = [0, 0, 0, 0, -1]
i would like to get a list with size equal to 5(K) filled with zeros except the positions that are specified in the input list on which the value will be -1(I didnt reverse it).
I think your code should be - note the list is built in the head, to avoid reversing)
create(_ ,N,K, []) :- N > K, !.
create([N|Xs],N,K,[-1|L]) :- !, N1 is N + 1, create(Xs,N1,K,L).
create( Xs ,N,K,[ 0|L]) :- N1 is N + 1, create(Xs,N1,K,L).
It requires the zeros positions sorted.
Otherwise, the more idiomatic - and cryptic -
create(Ps, N,K, L) :- findall(D, (
between(N,K,P),
( memberchk(P,Ps) -> D = -1 ; D = 0)), L).
will work regardless the ordering.