Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Split a list in half

Tags:

list

prolog

I need to define divide so that List [1,2,3,4,5] divides into:

a = [1,2,3}

b = [4,5]

I'm getting an error that says "Arguments are not sufficiently instantiated", and I don't know enough about the language to figure out what my problem is, or if my design is even right. Any guidance would be appreciated.

So here's what I have so far:

append([],L2,L2).
append([H|T],L2,[H|L3]) :- append(T,L2,L3).

lengthIs([],N).
lengthIs([H|T],N) :- lengthIs(T,M), N is M+1.

divide([],[],[]).
divide([H|T],L2,L3) :-
   (  lengthIs(L2, M) < lengthIs(L1,N)/2
   -> divide(T, append(L2, H, X), L3)
   ;  divide(T, L2, append(L3,H,Y))
   ).
like image 875
bdmflyer Avatar asked Nov 18 '11 00:11

bdmflyer


3 Answers

Let's give the predicate a more relational name: list_half_half/3

list_half_half(Xs, Ys, Zs) :-
   length(Xs, N),
   H is N - N // 2,
   length(Ys, H),
   append(Ys, Zs, Xs).

length/2 and append/3 are predefined in practically all recent Prologs.

This is GNU Prolog:

| ?- append(L,_,[a,b,c,d]), list_half_half(L,H1,H2).

H1 = []
H2 = []
L = [] ? ;

H1 = [a]
H2 = []
L = [a] ? ;

H1 = [a]
H2 = [b]
L = [a,b] ? ;

H1 = [a,b]
H2 = [c]
L = [a,b,c] ? ;

H1 = [a,b]
H2 = [c,d]
L = [a,b,c,d]
like image 57
false Avatar answered Oct 11 '22 12:10

false


This is the most efficient solution conforming to your specification for most Prolog implementations:

divide(L, A, B) :-
    divide1(L, L, A, B).

divide1([], L, [], L).
divide1([_|T], [H|L], [H|A], B) :-
    divide2(T, L, A, B).

divide2([], L, [], L).
divide2([_|T], L, A, B) :-
    divide1(T, L, A, B).

If you don't mind which elements go into the sublists as far as they are of similar length (as in the solution from Konstantin Weitz post), then you can use :

divide([], [], []).
divide([H|T], [H|A], B) :- divide(T, B, A).
like image 35
salva Avatar answered Oct 11 '22 10:10

salva


append is a pre-defined predicate, so that might be the issue: http://en.wikibooks.org/wiki/Prolog/Lists#The_append_predicate

You also never defined 'N' in lengthIs - you need to set the empty list as 0, not N/ There's likely also a size function

The underscore tells Prolog we don't care about that bit in that predicate definition.

Something like this should work

divide(L1,L2,L3):- append(L2,L3,L1), 
                   samesize(L2,L3).
divide(L1,L2,L3):- append(L2,L3,L1), 
                   onebigger(L2,L3).
samesize(A,B):-    size(A,N),
                   size(B,N).
onebigger(A,[_|T]):-   size(A,N), 
                   size(T,N).
size([],0).
size([H|T],N):-    size(T,M+1).
like image 4
Philip Whitehouse Avatar answered Oct 11 '22 12:10

Philip Whitehouse