@Boris answer does not end when the length of the list of the first argument is unknown. To see this, there is no need to look beyond the first step with failure-slice :
div (L, L1, L2, L3): -
length (L, Len), false ,
% here you compute for example Len1 and Len2
length (L1, Len1) ,
length (L2, Len2) ,
append (L1, L1_suffix, L) ,
append (L2, L3, L1_suffix) .
On the other hand, your original program had pretty nice termination properties . cTI gave the following optimal termination property:
div(A,B,C,D) terminates_if b(A);b(B);b(C);b(D).
In other words, to ensure completion, you only need one argument (either A , or B or C or D ) to be a specific list that is finite and ground (which is what b(..) means). This is a very strong termination condition. It is unfortunate that the arguments do not fit! Why not generalize your program? The only problem is that it restricts the list items. Therefore, I replaced all the variable names of the list items with _ s:
gdiv([], [], [], []). gdiv([_], [_], [], []). gdiv([_,_], [_], [_], []). gdiv([_,_,_|End], [_|XEnd], [_|YEnd], [_|ZEnd]):- gdiv(End, XEnd, YEnd, ZEnd).
the same completion properties for this program.
Alas, now this is too much. Borisβs decision can now be repackaged:
divnew(Zs, As, Bs, Cs) :- gdiv(Zs, As, Bs, Cs), append(As, BsCs, Zs), append(Bs, Cs, BsCs).
My preferred way of expressing the same is:
divnew(Zs, As, Bs, Cs) :- gdiv(Zs, As, Bs, Cs), phrase( ( seq(As), seq(Bs), seq(Cs) ), Zs).
See other answers for a definition of seq//1 .