I like Sergey's solution for its elegance and simplicity (+1). Here's another approach which is less elegant in favor of some further efficiency as it prunes the cases where append
is queried. If either A
or B
are ground, then we let their length drive the process. Otherwise, we let the length of L
drive it:
div(L, A, B) :-
( \+ground(A),
\+ground(B)
-> length(L, N),
HalfN is N div 2
; true
),
length(A, HalfN),
length(B, HalfN),
append(A, B, L).
And this will yield, for example:
| ?- div2(L, A, B).
A = []
B = []
L = [] ? ;
A = [C]
B = [D]
L = [C,D] ? ;
A = [C,D]
B = [E,F]
L = [C,D,E,F] ?
...
| ?- div([1,2,3|T], A, B).
A = [1,2]
B = [3,C]
T = [C] ? ;
A = [1,2,3]
B = [C,D,E]
T = [C,D,E] ? ;
...
| ?- div(L, [1,2], B).
B = [A,C]
L = [1,2,A,C]
yes
| ?- div([1,2|T], [1,2], [3,4]).
T = [3,4]
yes
| ?-
Etc.
length/2
as @larsmans pointed out, your solution still appears to try and construct the first half list, but it doesn't have any code to deal with the second half. You might need an auxiliary predicate to deal with a length counter. Alternatively, you can consider usingappend/3
. Fordiv(L, X, Y)
look atappend(X, Y, L)
and constrain the length ofX
orY
. – lurker