我遇到以下prolog代码的问题:
valid(X, Y) :-
append([E1 | T2], [E1 | T3], X1), append([E1|T1], X1, X),
append([E2 | T2], [E2 | T3], Y1), append([E2|T1], Y1, Y),
E2 is E1 + 1.
我要做的是:对于给定的列表X,检查它是否与模式[E1, ..., E1, ..., E1, ...]
匹配;如果是,请将所有E1
替换为E1+1
。
...
部分中可以包含任意数量的元素,即T1
,T2
和T3
可以是任意长度。
例如,我的预期输出是:
?- valid([1,5,1,6,7,1,8], Y).
Y = [2, 5, 2, 6, 7, 2, 8] ;
false.
?- valid([1,5,6,1,7,1], Y).
Y = [2, 5, 6, 2, 7, 2] ;
false.
?- valid([1,5,6,7,8], Y).
false.
但现在我得到的实际输出是:
?- valid([1,5,1,6,7,1,8], Y).
Y = [2, 5, 2, 6, 7, 2, 8] ;
ERROR: Out of global stack
?- valid([1,5,6,7,8], Y).
ERROR: Out of global stack
问题是,prolog将尝试尝试无限长度的T1
,T2
和T3
,因此永远不会停止。因此,当我的输入列表X
与模式不匹配时,它会一直运行直到内存空间不足。
有没有办法修复我的代码,以便在找到所有可能的答案(可能不止一个)或X与模式不匹配时停止?
谢谢!
答案 0 :(得分:2)
Append/3
谓词不是坚定的,所以它在开始时评估它的参数。所以你需要在前面移动评估X的规则,如:
valid(X, Y) :-
append([E1|T1], X1, X),append([E1 | T2], [E1 | T3], X1),
append([E2|T1], Y1, Y),append([E2 | T2], [E2 | T3], Y1),
E2 is E1 + 1.
由于X被评估,因此第一次附加不会导致尝试无限长度,并且类似地第二次追加。
一些例子:
?- valid([1,5,1,6,7,1,8], Y).
Y = [2, 5, 2, 6, 7, 2, 8] ;
false.
?- valid([1,5,6,1,7,1], Y).
Y = [2, 5, 6, 2, 7, 2] ;
false.
?- valid([1,5,6,7,8], Y).
false.
我更倾向于使用一些简单的递归和计算E1的外观来解决问题(并在输出列表中替换为E2),因为追加可能有点棘手......
例如:
:- use_module(library(clpfd)).
valid([H|T], [H2|T2]):- H2 #= H+1 ,valid(H,T,T2,1).
valid(_,[],[],3).
valid(H,[H|T1],[H2|T2],Count):- H2 #= H+1, Count1 #= Count+1,valid(H,T1,T2,Count1).
valid(H,[H1|T1],[H1|T2],Count):- dif(H1,H), valid(H,T1,T2,Count).
还有一些例子:
?- valid([1,5,1,6,7,1,8], Y).
Y = [2, 5, 2, 6, 7, 2, 8] ;
false.
?- valid([1,5,6,1,7,1], Y).
Y = [2, 5, 6, 2, 7, 2] ;
false.
?- valid([1,5,6,7,8], Y).
false.
?- valid(X, [2, 5, 2, 6, 7, 2, 8]).
X = [1, 5, 1, 6, 7, 1, 8] ;
false.
使用CLPFD库使谓词更具关系性,正如您在上面的上一个示例中所看到的,您可以在不能使用之前进行查询:valid(X, [2, 5, 2, 6, 7, 2, 8]).
(使用以前的解决方案)。
这是另一种替代方式:
new(H,H,R):- R is H+1.
new(H,N,N):- dif(N,H).
valid([H|T], Y):- findall(X1, (member(X1,[H|T]),X1 = H) , L),
length(L,3), maplist(new(H),[H|T],Y).