2

Below code works for split_list/3:

split_list([], _, [[],[]]).
split_list(T, 0, [[],T]).
split_list([H|T], N, [[H|Y],Z]) :-
   N1 is N-1,
   split_list(T, N1, [Y,Z]).

For example:

?- split_list([a,s,d,f,g,h,j], 3, R).
R = [[a, s, d], [f, g, h, j]] .              % observed answer

But, I want to convert split_list/3 to split/4:

?- split([a,s,d,f,g,h,j], 2, R1, R2).
R1 = [a,s], R2 = [d,f,g,h,j].                % expected answer

How can I get the answer that I want? Any suggestions? Thank you :)

repeat
  • 18,496
  • 4
  • 54
  • 166
komtan
  • 81
  • 1
  • 12

3 Answers3

4

Here's a straight-forward definition of split/4:

split(AsBs, N, As, Bs) :-
   append(As, Bs, AsBs),
   length(As, N).

Sample query as given by the OP:

?- split([a,s,d,f,g,h,j], 2, R1, R2).
   R1 = [a,s], R2 = [d,f,g,h,j]
;  false.

How about a generalisation of above query?

?- split([a,s,d,f,g,h,j], I, R1, R2).
   I = 0, R1 = [],              R2 = [a,s,d,f,g,h,j]
;  I = 1, R1 = [a],             R2 =   [s,d,f,g,h,j]
;  I = 2, R1 = [a,s],           R2 =     [d,f,g,h,j]
;  I = 3, R1 = [a,s,d],         R2 =       [f,g,h,j]
;  I = 4, R1 = [a,s,d,f],       R2 =         [g,h,j]
;  I = 5, R1 = [a,s,d,f,g],     R2 =           [h,j]
;  I = 6, R1 = [a,s,d,f,g,h],   R2 =             [j]
;  I = 7, R1 = [a,s,d,f,g,h,j], R2 =              [].
repeat
  • 18,496
  • 4
  • 54
  • 166
  • 1
    I'd kind-of suggest to put `length` in front, since `N` is most probably given. – false Jan 02 '16 at 22:52
  • @false. How about doing that but using a lazy implementation for the sake of preserving favorable termination properties? – repeat Jan 02 '16 at 23:04
  • 1
    For the simple, intended use case, your version leaves a CP. And it does not terminate for: `split(XsYs, 2, Xs, Ys)` – false Jan 03 '16 at 06:34
1

In this answer, we use constraints for expressing declarative integer arithmetic.

:- use_module(library(clpfd)).

We define split/4 by combining the code of append/3 and the code1 of fd_length/2.

Note the parallels of fd_length/2 with split/4 and of fd_length/3 with split_/5:

split(Zs, N, Xs, Ys) :-                  %%   fd_length(Xs, N) :-
   N #>= 0,                              %%      N #>= 0,
   split_(Xs, N,0, Ys, Zs).              %%      fd_length(Xs, N,0).
                                         %%
split_([], N,N0, Zs, Zs) :-              %%   fd_length([], N,N0) :-
   N #= N0.                              %%      N #= N0.
split_([X|Xs], N,N0, Ys, [X|Zs]) :-      %%   fd_length([_|Xs], N,N0) :-
   N1 #= N0+1,                           %%      N1 #= N0+1,
   N #>= N1,                             %%      N #>= N1,
   split_(Xs, N,N1, Ys, Zs).             %%      fd_length(Xs, N,N1).

Now, if look at the code of split_/5 again, then we can see the code of append/3 in it:

%% split_([], N,N0, Zs, Zs) :-           %%   append([], Zs, Zs).
%%    N #= N0,                           %% 
%% split_([X|Xs], N,N0, Ys, [X|Zs]) :-   %%   append([X|Xs], Ys, [X|Zs]) :-
%%    N1 #= N0+1,                        %% 
%%    N #>= N1,                          %% 
%%    split_(Xs, N,N1, Ys, Zs).          %%      append(Xs, Ys, Zs).

Sample queries:

?- N = 2, split(XsYs, N, Xs, Ys).
   XsYs = [_A,_B|Ys], N = 2, Xs = [_A,_B]
;  false.

?- N = 2, XsYs = [a,b,c,d,e], split(XsYs, N, Xs, Ys).
   XsYs = [a,b,c,d,e], N = 2, Xs = [a,b], Ys = [c,d,e]
;  false.

?- XsYs = [a,s,d,f,g,h,j], split(XsYs, N, Xs, Ys).
   XsYs = [a,s,d,f,g,h,j], N = 0, Xs = []             , Ys = [a,s,d,f,g,h,j]
;  XsYs = [a,s,d,f,g,h,j], N = 1, Xs = [a]            , Ys =   [s,d,f,g,h,j]
;  XsYs = [a,s,d,f,g,h,j], N = 2, Xs = [a,s]          , Ys =     [d,f,g,h,j]
;  XsYs = [a,s,d,f,g,h,j], N = 3, Xs = [a,s,d]        , Ys =       [f,g,h,j]
;  XsYs = [a,s,d,f,g,h,j], N = 4, Xs = [a,s,d,f]      , Ys =         [g,h,j]
;  XsYs = [a,s,d,f,g,h,j], N = 5, Xs = [a,s,d,f,g]    , Ys =           [h,j]
;  XsYs = [a,s,d,f,g,h,j], N = 6, Xs = [a,s,d,f,g,h]  , Ys =             [j]
;  XsYs = [a,s,d,f,g,h,j], N = 7, Xs = [a,s,d,f,g,h,j], Ys =              []
;  false.

?- Xs = [a,b,c], Ys = [d,e,f], split(XsYs, N, Xs, Ys).
XsYs = [a,b,c,d,e,f], N = 3, Xs = [a,b,c], Ys = [d,e,f].

Footnote 1: To accentuate the parallels, the program text of fd_length/2 (optimized variant) was altered slightly:
L was replaced by Xs, the argument pair N, N0 by N,N0, and (is)/2 by (#=)/2.

Community
  • 1
  • 1
repeat
  • 18,496
  • 4
  • 54
  • 166
0

if you are interested in preserving the semantic of your existing definition, you can reuse it in this way

split_list(L,N,R1,R2) :- split_list(L,N,[R1,R2]).
CapelliC
  • 59,646
  • 5
  • 47
  • 90