The code presented in this previous answer is quite versatile—thanks to clpfd.
Is there a downside? Yes, there is a downside: Inefficiency!
In this answer, we improve performance and preserve versatility.
:- use_module(library(clpfd)).
We proceed like this previous answer did when it defined the predicate fd_length/2
:
list_nth0_item_replaced__NEW(Es, N, X, Xs) :-
list_index0_index_item_replaced(Es, 0,N, X, Xs).
list_index0_index_item_replaced([_|Es], I ,I, X, [X|Es]).
list_index0_index_item_replaced([E|Es], I0,I, X, [E|Xs]) :-
I0 #< I,
I1 #= I0+1,
list_index0_index_item_replaced(Es, I1,I, X, Xs).
So... has it gotten any faster?
?- numlist(1,100000,Zs), time(list_nth0_item_replaced(Zs,99999,x,Xs)).
% 14,499,855 inferences, 0.893 CPU in 0.893 seconds (100% CPU, 16237725 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
Xs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 7 inferences, 0.000 CPU in 0.000 seconds (99% CPU, 18377 Lips)
false.
?- numlist(1,100000,Zs), time(list_nth0_item_replaced__NEW(Zs,99999,x,Xs)).
% 499,996 inferences, 0.049 CPU in 0.049 seconds (100% CPU, 10158710 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
Xs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 6 inferences, 0.000 CPU in 0.000 seconds (93% CPU, 213988 Lips)
false.
OK, it is faster. But is it still versatile?
?- list_nth0_item_replaced__NEW([a,b,c,d], 1, z, Xs).
Xs = [a,z,c,d]
; false.
?- list_nth0_item_replaced__NEW(Xs, 1, z, [a,z,c,d]).
Xs = [a,_A,c,d]
; false.
?- list_nth0_item_replaced__NEW(Es, N, X, [a,z,c,d]).
N = 0, X = a, Es = [_A, z, c, d],
; N = 1, X = z, Es = [ a,_A, c, d]
; N = 2, X = c, Es = [ a, z,_A, d],
; N = 3, X = d, Es = [ a, z, c,_A]
; false.
?- list_nth0_item_replaced__NEW([a,b,c,d], N, X, Xs).
N = 0, Xs = [X,b,c,d]
; N = 1, Xs = [a,X,c,d]
; N = 2, Xs = [a,b,X,d]
; N = 3, Xs = [a,b,c,X]
; false.
Looks alright to me!