替换Prolog中列表的元素

我有一个谓词variablize / 3,它接受一个列表并依次用一个变量替换每个项目,例如:

% ?- variablize([a,b,c], X, L).
% L = [[X, b, c], [a, X, c], [a, b, X]]

现在我试图扩展此谓词以接受变量列表,例如:

% ?- variablize([a,b,c], [X,Y], L).
% L = [[X, Y, c], [X, b, Y], [a, X, Y]]

到目前为止我的代码是:

replace_at([_|Tail], X, 1, [X|Tail]).
replace_at([Head|Tail], X, N, [Head|R]) :- M is N - 1, replace_at(Tail, X, M, R).

replace_each([], _, _, [], _).
replace_each([_|Next], Orig, X, [Res|L], N) :-
    replace_at(Orig, X, N, Res),
    M is N + 1,
    replace_each(Next, Orig, X, L, M).

variablize(I, X, L) :- replace_each(I, I, X, L, 1).

有什么指针吗?我是否将replace_at / 4扩展为具有应跳过的索引列表?

最佳答案 一种简化的,基于内置的实现variablize / 3的方法

variablize(I, X, L) :-
    bagof(R, U^select(U, I, X, R), L).

证明当X成为一个列表时,我们可以使用一个分配/ 3来代替select/4,而不是X的元素的替换. select / 4可以这种方式实现

myselect(B, I, X, R) :-
    append(A, [B|C], I), append(A, [X|C], R).

这个表单很方便,因为我们有输入列表I右边的部分,我想你需要分配剩余的变量.然后对X元素的递归应该:

distribute(I, [X|Xs], L) :-
    append(A, [_|C], I),
    distribute(C, Xs, R),
    append(A, [X|R], L).
distribute(I, [], I).

distribute / 3的行为方式如下:

?- distribute([a,b,c,d],[1,2],X).
X = [1, 2, c, d] ;
X = [1, b, 2, d] ;
X = [1, b, c, 2] ;
X = [a, 1, 2, d] ;
X = [a, 1, c, 2] ;
X = [a, b, 1, 2] ;
false.

从而

variablize_l(I, X, L) :-
    bagof(R, distribute(I, X, R), L).

给我们:

?- variablize_l([a,b,c],[X,Y],L).
L = [[X, Y, c], [X, b, Y], [a, X, Y]].

编辑

我最初是这样编写的,因为这里有将分发阶段与列表构造分开的证据:

replace_v([_|T], X, [X|T]).
replace_v([L|T], X, [L|R]) :-
    replace_v(T, X, R).
variablize(I, X, L) :-
    bagof(E, replace_v(I, X, E), L).
点赞