我有问题。我想实现替换(E1,L1,E2,L2)谓词。 当L1和L2是相同的列表时,这保持不变,除了在L1具有值E1的一个地方中,L2具有E2。此外,只更换一次,它必须在任何模式下工作。
例如:
replace(2,[1,2,3,4],5,X)
应该只有解决方案X = [1,5,3,4]
。
replace(2,[1,2,3,2,1],5,X)
应该回溯解决方案X =
[1,5,3,2,1]
和X = [1,2,3,5,1]
。
replace(2,X,5,[1,5,3,5,1])
应该回溯解决方案X =
[1,2,3,5,1]
和X = [1,5,3,2,1]
。
replace(X,[a,b,c,d],Y,[a,e,c,d])
应该只有解决方案X = b,
Y = e
。
replace(X,[1,2,3,2,1],Y,[1,5,3,5,1])
应该没有解决方案(它
应该失败)。
我的实施:
replace(E1, L1, E2, L2) :-
append(X, [E1|L_Tail], L1),
append(X, [E2|L_Tail], L2).
这段代码很好。但是,replace(2,X,5,[1,5,3,5,1])
时,它应返回X = [1,2,3,5,1]
和X = [1,5,3,2,1]
以及false
。它只返回前2个结果,false
没有出现。该程序以ERROR: Out of global stack
结束。
答案 0 :(得分:2)
This question,它有两个答案:one you used和better one。但是,我将回答“为什么这个解决方案不起作用以及如何修复它?”的问题。
当append/3
的第三个参数是变量或部分列表时,它会提供无限多个解决方案:
?- append(X, Y, [a|Z]).
X = [],
Y = [a|Z] ;
X = [a],
Y = Z ;
X = [a, _1860],
Z = [_1860|Y] ;
X = [a, _1860, _1872],
Z = [_1860, _1872|Y] ;
X = [a, _1860, _1872, _1884],
Z = [_1860, _1872, _1884|Y] . % and so on
因此,当第一个列表L1
是部分列表时,对append(X, [E1|Y], L1)
的调用将保持“幻觉”更长和更长的列表。对append/3
的第二次调用每次都会失败,Prolog会回溯,使用第一个append/3
制作更长的列表,依此类推。这就是为什么你陷入无限循环并最终耗尽内存(当列表变得太长时)。
避免这种情况的一种便宜方法是确保两个列表都是相同长度的正确列表,然后再将它们提供给两个append
。例如:
same_length([], []).
same_length([_|A], [_|B]) :- same_length(A, B).
如果您使用的是SWI-Prolog,可以使用maplist和yall
lambda执行此操作:
maplist([_,_]>>true, L1, L2)
示例查询:
?- L2 = [1,5,3,5,1],
maplist([_,_]>>true, L1, L2),
append(X, [2|Y], L1),
append(X, [5|Y], L2).
L2 = [1, 5, 3, 5, 1],
L1 = [1, 2, 3, 5, 1],
X = [1],
Y = [3, 5, 1] ;
L2 = [1, 5, 3, 5, 1],
L1 = [1, 5, 3, 2, 1],
X = [1, 5, 3],
Y = [1] ;
false.