TL;DR: To insert item E
at position I1
into list Es0
, we do not need to write recursive code.
Instead, we can delegate the work (and the worries about getting it right, too!) to versatile auxiliary predicates, all of which are part of the Prolog prologue. To define ins_/4
we write:
ins_(E, Es0, I1, Es) :-
maplist(any_thing, Es, [_|Es0]),
append(Prefix, Suffix, Es0),
length([_|Prefix], I1),
append(Prefix, [E|Suffix], Es).
any_thing(_, _). % auxiliary predicate (used above)
Note that maplist(any_thing, Es, [_|Es0])
is equivalent to same_length(Es, [_|Es0])
.
Sample queries1,2,3 using GNU Prolog version 1.4.4 (64-bit):
?- ins_(X, [a,b,c,d,e], N1, Xs).
N1 = 1, Xs = [X,a,b,c,d,e]
; N1 = 2, Xs = [a,X,b,c,d,e]
; N1 = 3, Xs = [a,b,X,c,d,e]
; N1 = 4, Xs = [a,b,c,X,d,e]
; N1 = 5, Xs = [a,b,c,d,X,e]
; N1 = 6, Xs = [a,b,c,d,e,X]
; false.
?- ins_(X, [a,b,c,d,e], 3, Xs).
Xs = [a,b,X,c,d,e]
; false.
?- ins_(X, Xs0, 3, [a,b,c,d,e]).
X = c, Xs0 = [a,b,d,e]
; false.
Let's not forget about the most general query!
?- ins(X, Es0, I1, Es).
Es0 = [], I1 = 1, Es = [X]
;
Es0 = [A], I1 = 1, Es = [X,A]
; Es0 = [A], I1 = 2, Es = [A,X]
;
Es0 = [A,B], I1 = 1, Es = [X,A,B]
; Es0 = [A,B], I1 = 2, Es = [A,X,B]
; Es0 = [A,B], I1 = 3, Es = [A,B,X]
;
Es0 = [A,B,C], I1 = 1, Es = [X,A,B,C]
; Es0 = [A,B,C], I1 = 2, Es = [A,X,B,C]
; Es0 = [A,B,C], I1 = 3, Es = [A,B,X,C]
; Es0 = [A,B,C], I1 = 4, Es = [A,B,C,X]
;
Es0 = [A,B,C,D], I1 = 1, Es = [X,A,B,C,D]
; ...
Fair enumeration of all solutions, OK!
EDIT:
I repeated the most general query with ins3/4
as defined
by @m09 in his answer on SWI-Prolog 7.3.11 and SICStus Prolog 4.3.2 (both feature the library predicate nth1/4
).
I was surprised to see the underlying implementations of nth1/4
exhibit different procedural semantics (w.r.t. "fair enumeration"). See for yourself!
% SICStus Prolog 4.3.2 % SWI Prolog 7.3.11
% %
?- ins3(X, Es0, I1, Es). % ?- ins3(X, Es0, I1, Es).
I1 = 1, Es0 = [], Es = [X] % I1 = 1, Es = [X|Es0]
; % ; I1 = 2, Es0 = [_A|_Z],
I1 = 1, Es0 = [_A], Es = [X,_A] % Es = [_A,X|_Z]
; I1 = 2, Es0 = [_A], Es = [_A,X] % ; I1 = 3, Es0 = [_A,_B|_Z],
; % Es = [_A,_B,X|_Z]
I1 = 1, Es0 = [_A,_B], Es = [X,_A,_B] % ; I1 = 4, Es0 = [_A,_B,_C|_Z],
; I1 = 2, Es0 = [_A,_B], Es = [_A,X,_B] % Es = [_A,_B,_C,X|_Z],
; I1 = 3, Es0 = [_A,_B], Es = [_A,_B,X] % ; I1 = 5, Es0 = [_A,_B,_C,_D|_Z],
; % Es = [_A,_B,_C,_D,X|_Z]
... % ...
Footnote 1: All sample queries shown above terminate universally.
Footnote 2: The answers given by the GNU Prolog toplevel have been pretty-printed a little.
Footnote 3: The code presented above is used as-is, no additional library predicates are required.