1

对于以下查询(以及以下定义的谓词),我得到了一个意想不到的答案:

?- 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).
4

3 回答 3

3

要允许每个列表有多个匹配项,请使用 maplist/3并按如下方式进行:

item_replacement_item_mapped(E, Es, E, Es)。
item_replacement_item_mapped(X, _, E, [E]) :-
   差异(X,E)。

复制(Es0,X,Xs,Es):-
   地图列表(item_replacement_item_mapped(X,Xs),Es0,Ess1),
   追加(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.
于 2015-12-22T11:54:01.647 回答
2

正如@repeat 已经很好地展示的那样,您应该使用约束dif/2来描述两个术语是不同的。这避免了意外和错误的第二种解决方案。

此外,与往常一样,在描述列表时,还可以考虑使用表示法:您可以使用非终结符list//1do 以声明方式描述列表,以便可以轻松有效地在特定位置将其拼接到其他列表中。

考虑:

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.

这是一种适用于所有方向的真实关系。它可以回答相当普遍的问题,例如:哪个项目已被另一个列表替换?例子:

?- 短语(替换([1,2,3],E,[2,3,4]),[1,2,2,3,4])。
E = 3 ;
错误的。
于 2015-12-22T13:19:13.137 回答
0

编辑

这越来越多毛了,我的回答并没有准确地考虑到请求......所以让我们看看你的代码有最小的变化:

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 与众所周知的 append/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
      ).
于 2015-12-22T10:45:16.163 回答