Prolog 错误:使用append/3超出全局堆栈
我有个问题。我想实现一个replace(E1,L1,E2,L2)谓词。 当L1和L2是相同的列表时,这一点成立,但在L1具有值E1的一个位置,L2具有E2。此外,只替换一个引用,它必须在任何模式下工作 例如:Prolog 错误:使用append/3超出全局堆栈,prolog,Prolog,我有个问题。我想实现一个replace(E1,L1,E2,L2)谓词。 当L1和L2是相同的列表时,这一点成立,但在L1具有值E1的一个位置,L2具有E2。此外,只替换一个引用,它必须在任何模式下工作 例如: same_length([], []). same_length([_|A], [_|B]) :- same_length(A, B). replace(2[1,2,3,4],5,X)应该只有解决方案X=[1,5,3,4] 替换(2[1,2,3,2,1],5,X)应回溯解决方案X= [1
same_length([], []).
same_length([_|A], [_|B]) :- same_length(A, B).
replace(2[1,2,3,4],5,X)
应该只有解决方案X=[1,5,3,4]
替换(2[1,2,3,2,1],5,X)
应回溯解决方案X=
[1,5,3,2,1]
和X=[1,2,3,5,1]
替换(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
替换(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
。它只返回前两个结果,false
没有出现。程序最终出现错误:已询问全局堆栈外,它有两个答案:和。但是,我将回答“为什么这个解决方案不起作用以及如何修复它?”的问题
当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
s之前,确保两个列表都是长度相同的正确列表。例如:
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.
已被询问,它有两个答案:和。但是,我将回答“为什么这个解决方案不起作用以及如何修复它?”的问题
当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
s之前,确保两个列表都是长度相同的正确列表。例如:
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.
嗨,鲍里斯,它工作了。你的回答清晰而有条理。非常感谢你!嗨,鲍里斯,它工作了。你的回答清晰而有条理。非常感谢你!