替换 Prolog 列表中元素的单次出现

Replace a single occurrence of an element in a list in Prolog

我得到了一个列表、一个要替换的元素以及该元素的替换项。我设法对该列表中出现的所有元素执行此操作:

replace([],X,Y,[]).
replace([X|T], X, Y, Z) :-
   replace(T, X, Y, Z1),
   Z = [Y|Z1].
replace([H|T], X, Y, [H|Z]) :-
   replace(T, X, Y, Z). 

但是现在我必须只替换该元素的第一次出现。 我的思考过程写作:

replace([X|T], X, Y, Z) :-
   replace(T, X, Y, Z1), 
   Z = [Y|Z1].

是:
Z[X|T],X,Y 的结果,如果 Z1TXYZ = [Y|Z1] 的结果。按照相同的思考过程,我尝试编写仅替换第一次出现的元素的函数,如下所示:

一个只实现第一次出现的想法是从 replace/4 进入 replace/5 ,如果我更换或不这样,我会计算:

replace_single(L,X,Y,Z) :- 
   replace2(L,X,Y,0,Z).

replace2([],X,Y,C,[]).
replace2([X|T], X, Y, C, Z) :-
   \+ (C = 0),
   replace2(T, X, Y, C, Z1),
   Z = [X|Z1],
   C is 1.
replace2([H|T], X, Y, C, [H|Z]) :-
   replace2(T, X, Y, C, Z).

显然不行,我有点迷茫。有人可以告诉我如何解决问题或解决方案本身吗?

我们根据same_length/2append/3, maplist/2, and :

定义replace/4
replace(Xs,X,Y,Ys) :-
   same_length(Xs,Ys),
   append(Prefix,[X|Suffix],Xs),
   maplist(dif(X),Prefix),
   append(Prefix,[Y|Suffix],Ys).

示例查询:

?- replace(Xs,2,two,[1,two,3,4,5,1,2,3,4,5,1,2]).
  Xs = [1,2,3,4,5,1,2,3,4,5,1,2]
; false.

?- replace([1,2,3,4,5,1,2,3,4,5,1,2],2,two,Ys).
  Ys = [1,two,3,4,5,1,2,3,4,5,1,2]
; false.

另一种方法是使用 DCG:

rep1(X, Y, [Z|T]) --> [Z], { dif(Z, X) }, rep1(X, Y, T).
rep1(X, Y, [Y|T]) --> [X], rest(T).
rep1(_, _, []) --> [].

rest([]) --> [].
rest([H|T]) --> [H], rest(T).

| ?- phrase(rep1(a, 1, L), [a,b,c,a,d]).

L = [1,b,c,a,d] ? ;

| ?- phrase(rep1(a, 1, [x, y, 1, b]), L).

L = [x,y,1,b] ? a

L = [x,y,a,b]

您可以将谓词写成:

replace(X, Y, L, R) :- phrase(rep1(X, Y, R), L).

另一种方法是:-

replace(E1,L1,E2,L2) :-
same_length(L1,L2),
append(BeforeElement,[E1|AfterElement],L1),
append(BeforeElement,[E2|AfterElement],L2).

其中 BeforeElement 代表元素之前列表的前缀,After Element 代表元素之后列表的后缀。