当第一个参数列表的长度未知时,@Boris 的答案不会终止。要看到这一点,无需再看第一个带有failure-slice的目标:
格(L,L1,L2,L3):-
length(L, Len), false ,
% 在这里你计算例如 Len1 和 Len2
length(L1, Len1) ,
length(L2, Len2) ,
append(L1, L1_suffix, L) ,
append(L2, L3, L1_suffix)。
另一方面,您的原始程序具有非常好的终止属性。cTI 给出了以下最佳终止属性:
div(A,B,C,D) terminates_if b(A);b(B);b(C);b(D).
换句话说,为了确保终止,您只需要一个参数(或者A
orB
或C
or D
)作为一个具体的列表,它是有限的和接地的(这就是b(..)
意思)。这是一个非常强的终止条件。论据不符,真是太可惜了!为什么不概括您的程序?它唯一的问题是它限制了列表元素。所以我将列表元素的所有变量名替换为_
s:
gdiv([], [], [], []).
gdiv([_], [_], [], []).
gdiv([_,_], [_], [_], []).
gdiv([_,_,_|End], [_|XEnd], [_|YEnd], [_|ZEnd]):-
gdiv(End, XEnd, YEnd, ZEnd).
该程序具有完全相同的终止属性。
唉,现在有点太笼统了。Boris 的解决方案现在可以重新利用:
divnew(Zs, As, Bs, Cs) :-
gdiv(Zs, As, Bs, Cs),
append(As, BsCs, Zs),
append(Bs, Cs, BsCs).
我更喜欢的表达方式是:
divnew(Zs, As, Bs, Cs) :-
gdiv(Zs, As, Bs, Cs),
phrase( ( seq(As), seq(Bs), seq(Cs) ), Zs).
有关的定义,请参见其他答案seq//1
。