4

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

% ?- 变量([a,b,c], X, L)。
% L = [[X, b, c], [a, X, c], [a, b, X]]

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

% ?- 变量([a,b,c], [X,Y], L)。
% L = [[X, Y, c], [X, b, Y], [a, X, Y]]

到目前为止,我的代码是:

替换_at([_|尾巴],X,1,[X|尾巴])。
replace_at([Head|Tail], X, N, [Head|R]) :- M 是 N - 1,replace_at(Tail, X, M, R)。

替换_每个([],_,_,[],_)。
replace_each([_|Next], 原点, X, [Res|L], N) :-
    replace_at(原点,X,N,Res),
    M 是 N + 1,
    replace_each(下一个,原点,X,L,M)。

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

任何指针?我是否扩展replace_at/4了应该跳过的索引列表?

4

2 回答 2

2

一种简化的、基于内置的实现方式variablize/3

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

证明当 X 变成一个列表时,我们可以有一个distribute/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).
于 2012-04-15T14:49:23.380 回答
0
variablize(L1,L2,L) :-
    append(L1,L2,L3),
    length(L1,Len1),
    length(L2,Len2),
    findall(L4,(combination(L3,Len1,L4),var_count(L4,Len2)),L).

combination(X,1,[A]) :-
    member(A,X).
combination([A|Y],N,[A|X]) :-
    N > 1,
    M is N - 1,
    combination(Y,M,X).
combination([_|Y],N,A) :-
    N > 1,
    combination(Y,N,A).

var_count([],0).
var_count([V|R],N) :-
    var(V),
    var_count(R,N1),
    N is N1 + 1,
    !.
var_count([A|R],N) :-
    var_count(R,N).
于 2012-04-17T05:22:36.380 回答