对于以下查询(以及下面定义的谓词),我得到一个意外的答案:
?- rep([1,2,3], 3, [2,3,4], L).
L = [1, 2, 2, 3, 4] ;
L = [1, 2, 3]. % unexpected answer
第一个结果是我想要的结果。第二个我不想要......
如何防止第二个?可能在某处添加!
?
concat([], L, L).
concat([H|T], L, [H|Res]) :-
concat(T, L, Res).
repl([], _, _, []).
repl([Val|T], Val, Repl, Res) :-
repl(T, Val, Repl, Temp),
concat(Repl, Temp, Res).
repl([H|T], Val, Repl, [H|Res]) :-
repl(T, Val, Repl, Res).
答案 0 :(得分:2)
要允许每个列表包含多个匹配项,请使用meta-predicate maplist/3
并按以下步骤操作:
item_replacement_item_mapped(E, Es, E, Es). item_replacement_item_mapped(X, _, E, [E]) :- dif(X, E). repl(Es0,X,Xs,Es) :- maplist(item_replacement_item_mapped(X,Xs), Es0, Ess1), append(Ess1, Es).
示例查询:
?- repl([1,2,3], 3, [2,3,4], L).
L = [1,2,2,3,4]
; false.
?- repl([x,y,x,y,x], x, [x,y,x], L).
L = [x,y,x,y,x,y,x,y,x,y,x]
; false.
答案 1 :(得分:2)
由于@repeat已经很好地显示,你应该使用约束dif/2
来描述两个术语是不同的。这避免了意外和错误的第二种解决方案。
此外,与描述列表时一样,还要考虑使用dcg表示法:您可以使用非终结符list//1
以声明方式描述列表,以便可以轻松高效地拼接到列表中特定职位的其他名单。
考虑:
replacement([], _, _) --> [].
replacement([L|Ls], L, Rs) -->
list(Rs),
replacement(Ls, L, Rs).
replacement([L|Ls], R, Rs) --> [L],
{ dif(L, R) },
replacement(Ls, R, Rs).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
我们使用接口谓词phrase/2
来使用DCG。例如:
?- phrase(replacement([1,2,3], 3, [2,3,4]), Ls).
Ls = [1, 2, 2, 3, 4] ;
false.
这是一个真正的关系,可以在各个方向发挥作用。它可以回答相当普遍的问题,例如:哪个项目已被其他列表替换?示例:
?- phrase(replacement([1,2,3], E, [2,3,4]), [1,2,2,3,4]). E = 3 ; false.
答案 2 :(得分:0)
修改的
这种情况变得多毛了,我的回答并没有准确地说明请求......所以让我们通过 minimal 更改看你的代码:
concat([], L, L).
concat([H|T], L, [H|Res]) :-
concat(T, L, Res).
repl([], _, _, []).
repl([Val|T], Val, Repl, Res) :- !, % as noted by @repeat, better to commit early...
repl(T, Val, Repl, Temp),
concat(Repl, Temp, Res). % !.
repl([H|T], Val, Repl, [H|Res]) :-
repl(T, Val, Repl, Res).
剪切只是提交第二个条款......
恢复旧答案
你的concat / 3与众所周知的追加/ 3相同,所以请考虑这种方法
repl(ListOrig, Element, Replace, ListUpdated) :-
append(H, [Element|T], ListOrig),
append(H, Replace, Temp),
append(Temp, T, ListUpdated).
?- repl([1, 2, 3], 3, [2, 3, 4], L).
L = [1, 2, 2, 3, 4] ;
false.
修改的
根据评论的要求,此扩展处理要匹配更改的元素列表,使用简单的模式匹配(注意:在前一个子句之前添加)
repl(ListOrig, [], _Replace, ListOrig).
repl(ListOrig, [E|Es], Replace, ListUpdated) :-
repl(ListOrig, E, Replace, Temp),
repl(Temp, Es, Replace, ListUpdated).
测试
?- repl([1,2,3],[2,3],[x,y,z],R).
R = [1, x, y, z, x, y, z] ;
false.
修改的
我没有注意到如果找不到Element就不应该失败...... 最后一个' catchall'子句可以处理这种情况:
repl(ListOrig, _Element, _Replace, ListOrig).
或更好,扩展原始
repl(ListOrig, Element, Replace, ListUpdated) :-
( append(H, [Element|T], ListOrig)
-> append(H, Replace, Temp),
append(Temp, T, ListUpdated)
; ListOrig = ListUpdated
).