1- prefix_by_index predicate will take the Index I, the List [a,b,c], and will give the final output in Prefix.
2- length predicate will calculate the length of the list and then subtract it with I as you have stated "The index always has this formula (length-i)". This value I1 is passed onto the p predicate that will act as a counter.
3- In the p predicate [H|T]=[a,b,c], C=I1, and [H|Prefix] will give us a list that will be our final output. C keeps decreasing and H at each iteration (a then b then c) is pushed into the [H|Prefix] list till the base case succeeds i.e. p(_,0,[]), C becomes zero.
prefix_by_index(I,List,Prefix):-
length(List,Len),
I1 is Len-I,
p(List,I1,Prefix).
p(_,0,[]):-!.
p([H|T],C,[H|Prefix]):-
C1 is C-1,
p(T,C1,Prefix).
Example:
?- prefix_by_index(1,[a,b,c],Prefix).
Prefix = [a, b]
?-prefix_by_index(2,[a,b,c],Prefix).
Prefix = [a]
?-prefix_by_index(3,[a,b,c],Prefix).
Prefix = []