how should I delete non numbers in list use prolog - list

I should remove all elements of List that are not a number greater than number. I can solve it just for numbers. but when the list has some symbolic how should I delete.this is my code
greater_nrs_only( X, List, Ans) :-
greater_nrs_only( X, List, Ans, [] ), !.
greater_nrs_only( _, [], Ans, Ans).
greater_nrs_only( X, [H | Tail], Ans, Acc ) :-
(
( H < X, NewEl = [] )
;
( H >= X, NewEl = [H] )
),
append( Acc, NewEl, NewAcc ),
greater_nrs_only( X, Tail, Ans, NewAcc).
and ?- greater_nrs_only(6, [ ], X).
is false

The reason this will error is because H is not per se a number, so comparing 6 with a for example will raise an error. You can use number/1 [swi-doc] to check if something is a number.
Instead of doing filtering manually, you can also work with include/3 [swi-doc], which filters the list for items that satisfy a given predicate:
greater_than(X, Y) :-
number(Y),
X < Y.
greater_nrs_only(X, L, R) :-
include(greater_than(X), L, R).

Related

Prolog: P-12: Ninety-Nine Prolog Problems (Modified)

I am trying to decode a specific list with two different elements, either e.g. [4, a] or just b
I expect decode([[4,a],b,[2,c],[2,a],d,[4,e]], X). to result into X=[a,a,a,a,b,c,c,a,a,d,e,e,e,e].
with
decode([], []).
decode([[N, X]|Xs], R) :-
create_list(N, X, L1),
append(L1, R),
decode(Xs, R).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
create_list(0, _, []).
create_list(N, X, [X|R]) :-
N > 0,
N1 is N - 1,
create_list(N1, X, R).
Generates only false and I have tested the create_list predicate and it works.
I have no clue what I'm missing but could just be a minor mistake. But I have tried for a while to find the problem without success so why not ask here :) The question is a modified version from the Ninety-Nine Prolog Problems (Problem 12).
Your problem lies in the use of append/2 which concatenates a list of lists, but you have a list of atoms.
You may use append/3 to build a list with an unbound tail and pass that tail to the recursive step of your procedure, i.e.:
decode([], []).
decode([[N, X]|Xs], R) :-
create_list(N, X, L1),
append(L1, Tail, R),
decode(Xs, Tail).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
create_list(0, _, []).
create_list(N, X, [X|R]) :-
N > 0,
N1 is N - 1,
create_list(N1, X, R).
Sample run:
?- decode([[4,a],b,[2,c],[2,a],d,[4,e]], X).
X = [a, a, a, a, b, c, c, a, a, d, e, e, e, e] ;
false.
You may also get rid of append altogether by adding a third argument to create_list which holds that tail:
decode([], []).
decode([[N, X]|Xs], R) :-
create_list(N, X, R, Tail),
decode(Xs, Tail).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
create_list(0, _, Tail, Tail).
create_list(N, X, [X|R], Tail) :-
N > 0,
N1 is N - 1,
create_list(N1, X, R, Tail).
Alternatively you may get rid of create_list by using length/2 and maplist/2:
decode([], []).
decode([[N, X]|Xs], R) :-
length(L, N),
maplist(=(X), L),
append(L, Tail, R),
decode(Xs, Tail).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
This is a problem of run-length encoding and run-length decoding.
Run-length encoding is easy:
encode( [] , [] ) . % the run-length encoding of the empty list is the empty list
encode( [X|Xs] , [R|Ys] ) :- % For non-empty lists,
run(Xs,X:1,R,Rs), % - seed the run with the first element and compute the run length
encode(Rs, Ys) % - then recurse down
. % Easy!
run( [] , Y:N , Y:N , [] ) .
run( [X|Xs] , Y:N , Y:N , [X|Xs] ) :- X \== Y .
run( [X|Xs] , Y:T , N , Rs ) :- X == Y , T1 is T+1 , run(Xs,Y:T1,N,Rs) .
And decoding a run-length encoded list is the opposite
decode( [] , [] ) . % the run-length decoding of the empty list is the empty list
decode( [X:N|Xs] , Ys ) :- % for non-empty lists,
expand(X,N,Ys,Zs) , % - expand the run
decode(Xs,Zs) % - recurse down
.
expand( _ , 0 , Zs , Zs ) .
expand( X , N , [X|Ys] , Zs ) :-
N > 0,
N1 is N-1,
expand(X,N1,Ys,Zs)
.
And then put it together in a transcoder that will work bi-directionally:
run_length_transcode( PlainText, RleText ) :- nonvar( PlainText ) , encode( PlainText , RleText ).
run_length_transcode( PlainText, RleText ) :- nonvar( RleText ) , decode( RleText , PlainText ).

DCG and inversion of a list in Prolog

I'm trying to count the numer of inversions in a list. A predicate inversion(+L,-N) unifies N to the number of inversions in that list. A inversion is defined as X > Y and X appears before Y in the list (unless X or Y is 0). For example:
?- inversions([1,2,3,4,0,5,6,7,8],N).
N = 0.
?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3.
For what I'm using this for, the list will always have exacly 9 elements, and always containing the numbers 0-8 uniquely.
I'm quite new to Prolog and I'm trying to do this as concise and as elegant as possible; It seems like DCG will probably help a lot. I read into the official definition and some tutorial sites, but still don't quit understand what it is. Any help would be greatly appreciated.
Here is another solution that doesn't leave choice points using if_/3:
inversions([],0).
inversions([H|T], N):-
if_( H = 0,
inversions(T,N),
( find_inv(T,H,N1),inversions(T, N2), N #= N1+N2 )
).
find_inv([],_,0).
find_inv([H1|T],H,N1):-
if_( H1=0,
find_inv(T,H,N1),
if_( H#>H1,
(find_inv(T,H,N2),N1 #= N2+1),
find_inv(T,H,N1)
)
).
#>(X, Y, T) :-
( integer(X),
integer(Y)
-> ( X > Y
-> T = true
; T = false
)
; X #> Y,
T = true
; X #=< Y,
T = false
).
I'm not so sure a DCG would be helpful here. Although we're processing a sequence, there's a lot of examination of the entire list at each point when looking at each element.
Here's a CLPFD approach which implements the "naive" algorithm for inversions, so it's transparent and simple, but not as efficient as it could be (it's O(n^2)). There's a more efficient algorithm (O(n log n)) involving a divide and conquer approach, which I show further below.
:- use_module(library(clpfd)).
inversions(L, C) :-
L ins 0..9,
all_distinct(L),
count_inv(L, C).
% Count inversions
count_inv([], 0).
count_inv([X|T], C) :-
count_inv(X, T, C1), % Count inversions for current element
C #= C1 + C2, % Add inversion count for the rest of the list
count_inv(T, C2). % Count inversions for the rest of the list
count_inv(_, [], 0).
count_inv(X, [Y|T], C) :-
( X #> Y, X #> 0, Y #> 0
-> C #= C1 + 1, % Valid inversion, count it
count_inv(X, T, C1)
; count_inv(X, T, C)
).
?- inversions([1,2,3,4,0,5,6,7,8],N).
N = 0 ;
false.
?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3 ;
false.
?- inversions([0,2,X],1).
X = 1 ;
false.
It does leave a choice point, as you can see, which I haven't sorted out yet.
Here's the O(n log n) solution, which is using the sort/merge algorithm.
inversion([], [], 0).
inversion([X], [X], 0).
inversion([HU1, HU2|U], [HS1, HS2|S], C) :- % Ensure list args have at least 2 elements
split([HU1, HU2|U], L, R),
inversion(L, SL, C1),
inversion(R, SR, C2),
merge(SL, SR, [HS1, HS2|S], C3),
C #= C1 + C2 + C3.
% Split list into left and right halves
split(List, Left, Right) :-
split(List, List, Left, Right).
split(Es, [], [], Es).
split(Es, [_], [], Es).
split([E|Es], [_,_|T], [E|Ls], Right) :-
split(Es, T, Ls, Right).
% merge( LS, RS, M )
merge([], RS, RS, 0).
merge(LS, [], LS, 0).
merge([L|LS], [R|RS], [L|T], C) :-
L #=< R,
merge(LS, [R|RS], T, C).
merge([L|LS], [R|RS], [R|T], C) :-
L #> R, R #> 0 #<==> D, C #= C1+D,
merge([L|LS], RS, T, C1).
You can ignore the second argument, which is the sorted list (just a side effect if all you want is the count of inversions).
Here is another possibility to define the relation. First, #</3 and #\=/3 can be defined like so:
:- use_module(library(clpfd)).
bool_t(1,true).
bool_t(0,false).
#<(X,Y,Truth) :- X #< Y #<==> B, bool_t(B,Truth).
#\=(X,Y,Truth) :- X #\= Y #<==> B, bool_t(B,Truth).
Based on that, if_/3 and (',')/3 a predicate inv_t/3 can be defined, that yields true in the case of an inversion and false otherwise, according to the definition given by the OP:
inv_t(X,Y,T) :-
if_(((Y#<X,Y#\=0),X#\=0),T=true,T=false).
And subsequently the actual relation can be described like so:
list_inversions(L,I) :-
list_inversions_(L,I,0).
list_inversions_([],I,I).
list_inversions_([X|Xs],I,Acc0) :-
list_x_invs_(Xs,X,I0,0),
Acc1 #= Acc0+I0,
list_inversions_(Xs,I,Acc1).
list_x_invs_([],_X,I,I).
list_x_invs_([Y|Ys],X,I,Acc0) :-
if_(inv_t(X,Y),Acc1#=Acc0+1,Acc1#=Acc0),
list_x_invs_(Ys,X,I,Acc1).
Thus the example queries given by the OP succeed deterministically:
?- list_inversions([1,2,3,4,0,5,6,7,8],N).
N = 0.
?- list_inversions([1,2,3,0,4,6,8,5,7],N).
N = 3.
Such application-specific constraints can often be built using reified constraints (constraints whose truth value is reflected into a 0/1 variable). This leads to a relatively natural formulation, where B is 1 iff the condition you want to count is satisfied:
:- lib(ic).
inversions(Xs, N) :-
( fromto(Xs, [X|Ys], Ys, [_]), foreach(NX,NXs) do
( foreach(Y,Ys), param(X), foreach(B,Bs) do
B #= (X#\=0 and Y#\=0 and X#>Y)
),
NX #= sum(Bs) % number of Ys that are smaller than X
),
N #= sum(NXs).
This code is for ECLiPSe.
Using clpfd et automaton/8 we can write
:- use_module(library(clpfd)).
inversions(Vs, N) :-
Vs ins 0..sup,
variables_signature(Vs, Sigs),
automaton(Sigs, _, Sigs,
[source(s),sink(i),sink(s)],
[arc(s,0,s), arc(s,1,s,[C+1]), arc(s,1,i,[C+1]),
arc(i,0,i)],
[C], [0], [N]),
labeling([ff],Vs).
variables_signature([], []).
variables_signature([V|Vs], Sigs) :-
variables_signature_(Vs, V, Sigs1),
variables_signature(Vs, Sigs2),
append(Sigs1, Sigs2, Sigs).
variables_signature_([], _, []).
variables_signature_([0|Vs], Prev, Sigs) :-
variables_signature_(Vs,Prev,Sigs).
variables_signature_([V|Vs], Prev, [S|Sigs]) :-
V #\= 0,
% Prev #=< V #<==> S #= 0,
% modified after **false** remark
Prev #> V #<==> S,
variables_signature_(Vs,Prev,Sigs).
examples :
?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3 ;
false.
?- inversions([1,2,3,0,4,5,6,7,8],N).
N = 0 ;
false.
?- inversions([0,2,X],1).
X = 1.
in SWI-Prolog, with libraries aggregate and lists:
inversions(L,N) :-
aggregate_all(count, (nth1(P,L,X),nth1(Q,L,Y),X\=0,Y\=0,X>Y,P<Q), N).
both libraries are autoloaded, no need to explicitly include them.
If you want something more general, you can see the example in library(clpfd), under the automaton section, for some useful ideas. But I would try to rewrite your specification in simpler terms, using element/3 instead of nth1/3.
edit
after #false comment, I tried some variation on disequality operators, but none I've tried have been able to solve the problematic query. Then I tried again with the original idea, to put to good use element/3. Here is the result:
:- use_module(library(clpfd)).
inversions(L) :-
L ins 0..8,
element(P,L,X),
element(Q,L,Y),
X #\= 0, Y #\= 0, X #> Y, P #< Q,
label([P,Q]).
inversions(L,N) :-
aggregate(count, inversions(L), N) ; N = 0.
The last line label([P,Q]) it's key to proper reification: now we can determine the X value.
?- inversions([0,2,X],1).
X = 1.

Prolog - Returning a List from a Recursive Predicate

I am using GNU-Prolog, and I have the following code that finds the numbers less than X which are divisible by Y. Assume X and Y > 0.
find_num(X, Y) :-
findall(N, between(1,X,N), List),
check_list(List, Y).
check_list([Head|Tail], Y) :-
(
divides(Head, Y) ->
format('~w ~s ~w ~n', [Head, "divisible by", Y]);
true
),
check_list(Tail, Y).
divides(X, Y) :-
X mod Y =:= 0.
The code outputs a text for the numbers, but I want the result to be a list like X = [1,2,3].
I tried multiple ways to make the list, but didn't succeed, examples:
check_list([Head|Tail], Y) :-
(
divides(Head, Y) ->
findall( X, determine_item(Head, X), List );
true
),
check_list(Tail, Y).
or
find_num(X, Y) :-
findall(N, between(1,X,N), List),
findall(N, check_list(List, Y, N), List2),
write(List2).
check_list([Head|Tail], Y, _) :-
(
divides(Head, Y) ->
Head;
true
),
check_list(Tail, Y).
divides(X, Y) :-
X mod Y =:= 0.
Any help would be appreciated.
If you want a list, your find_num (and your check_list) needs a third argument so...
What about
divides(X, Y) :-
X mod Y =:= 0.
find_num(X, Y, Lout) :-
findall(N, between(1, X, N), Lin),
check_list(Lin, Y, Lout).
check_list([], _, []).
check_list([H | Tin], Y, [H | Tout]) :-
divides(H, Y),
check_list(Tin, Y, Tout).
check_list([H | Tin], Y, Lout) :-
\+ divides(H, Y),
check_list(Tin, Y, Lout).
?

How to predicate all pairs in a given list in Prolog?

When given a list I would like to compute all the possible combinations of pairs in the list.
e.g 2) input is a list (a,b,c) I would like to obtain pairs (a,b) (a,c) (b,c)
e.g 1) input is a list (a,b,c,d) I would like to obtain pairs (a,b) (a,c) (a,d) (b,c) (b,d) and (c,d)
Using select/3 twice (or select/3 once and member/2 once) will allow you to achieve what you want here. I'll let you work out the details and ask for help if it's still troublesome.
BTW, Prolog syntax for list isn't (a, b, c) but [a, b, c] (well, it's syntactic sugar but I'll leave it at that).
edit: as #WillNess pointed out, you're not looking for any pair (X, Y) but only for pairs where X is before Y in the list.
DCGs are a really good fit: as #false described, they can produce a graphically appealing solution:
... --> [] | [_], ... .
pair(L, X-Y) :-
phrase((..., [X], ..., [Y], ...), L).
Alternatively, if you use SWI-Prolog, a call to append/2 does the trick too, in a similar manner, but is less efficient than DCGs:
pair2(L, X-Y) :-
append([_, [X], _, [Y], _], L).
You can do it with a basic recursion, as #WillNess suggested in his comment. I'll leave this part for him to detail if needed!
OK, so to translate the Haskell definition
pairs (x:xs) = [ (x,y) | y <- xs ]
++ pairs xs
pairs [] = []
(which means, pairs in the list with head x and tail xs are all the pairs (x,y) where y is in xs, and also the pairs in xs; and there's no pairs in an empty list)
as a backtracking Prolog predicate, producing the pairs one by one on each redo, it's a straightforward one-to-one re-write of the above,
pair( [X|XS], X-Y) :- member( ... , XS) % fill in
; pair( XS, ... ). % the blanks
%% pair( [], _) :- false.
To get all the possible pairs, use findall:
pairs( L, PS) :- findall( P, pair( L, P), PS).
Consider using bagof if your lists can contain logical variables in them. Controlling bagof's backtracking could be an intricate issue though.
pairs can also be written as a (nearly) deterministic, non-backtracking, recursive definition, constructing its output list through an accumulator parameter as a functional programming language would do -- here in the top-down manner, which is what Prolog so excels in:
pairs( [X|T], PS) :- T = [_|_], pairs( X, T, T, PS, []).
pairs( [_], []).
pairs( [], []).
pairs( _, [], [], Z, Z).
pairs( _, [], [X|T], PS, Z) :- pairs( X, T, T, PS, Z).
pairs( X, [Y|T], R, [X-Y|PS], Z) :- pairs( X, T, R, PS, Z).
Here is a possible way of solving this.
The following predicate combine/3 is true
if the third argument corresponds to a list
contains pairs, where the first element of each pair
is equal to the first argument of combine/3.
The second element of each pair will correspond to an item
of the list in the second argument of the predicate combine/3.
Some examples how combine/3 should work:
?- combine(a,[b],X).
X = [pair(a,b)]
?- combine(a,[b,c,d],X).
X = [pair(a,b), pair(a,c), pair(a,d)]
Possible way of defining combine/3:
combine(A,[B],[pair(A,B)]) :- !.
combine(A,[B|T],C) :-
combine(A,T,C2), % Create pairs for remaining elements in T.
append([pair(A,B)],C2,C). % Append current pair and remaining pairs C2.
% The result of append is C.
Now combine/3 can be used to define pair/2:
pairs([],[]). % Empty list will correspond to empty list of pairs.
pairs([H|T],P) :- % In case there is at least one element.
nonvar([H|T]), % In this case it expected that [H|T] is instantiated.
pairs(H,T,P).
pairs(A,[B],[pair(A,B)]) % If remaining list contains exactly one element,
:- !. % then there will be only one pair(A,B).
pairs(A,[B|T],P) :- % In case there are at least two elements.
combine(A,[B|T],P2), % For each element in [B|T] compute pairs
% where first element of each pair will be A.
pairs(B,T,P3), % Compute all pairs without A recursively.
append(P2,P3,P). % Append results P2 and P3 together.
Sample usage:
?- pairs([a,b,c],X).
X = [pair(a, b), pair(a, c), pair(b, c)].
?- pairs([a,b,c,d],X).
X = [pair(a, b), pair(a, c), pair(a, d), pair(b, c), pair(b, d), pair(c, d)].
You can use append/ to iterate through the list:
?- append(_,[X|R],[a,b,c,d]).
X = a,
R = [b, c, d] ;
X = b,
R = [c, d] ;
X = c,
R = [d] ;
X = d,
R = [] ;
false.
Next, use member/2 to form a pair X-Y, for each Y in R:
?- append(_,[X|R],[a,b,c,d]), member(Y,R), Pair=(X-Y).
X = a,
R = [b, c, d],
Y = b,
Pair = a-b ;
X = a,
R = [b, c, d],
Y = c,
Pair = a-c ;
X = a,
R = [b, c, d],
Y = d,
Pair = a-d ;
X = b,
R = [c, d],
Y = c,
Pair = b-c ;
X = b,
R = [c, d],
Y = d,
Pair = b-d ;
X = c,
R = [d],
Y = d,
Pair = c-d ;
false.
Then, use findall/3 to collect all pairs in a list:
?- findall(X-Y, (append(_,[X|R],[a,b,c,d]), member(Y,R)), Pairs).
Pairs = [a-b, a-c, a-d, b-c, b-d, c-d].
Thus, your final solution can be expressed as:
pairs(List, Pairs) :-
findall(X-Y, (append(_,[X|R],List), member(Y,R)), Pairs).
An example of use is:
?- pairs([a,b,c,d], Pairs).
Pairs = [a-b, a-c, a-d, b-c, b-d, c-d].

Split a list in half

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))
).
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]
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).
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).
Surely the effect of this code (lengthIs(L2, M) < lengthIs(L1,N)/2 -> ...) isn't what you expect: it doesn't compare numbers, but terms. You should write it this way:
lengthIs(L2, M), lengthIs(L1, N), M < N/2 -> ...
Another typo like mistake: the first clause of lengthIs/2 should read
lengthIs([],0).
No need to check sizes. Just do it like this:
div([],[],[]).
div([A],[A],[]).
div([A,B|T],[A|X],[B|Y]) :- div(T,X,Y).
Here's a sort of "rabbit and hare" approach.
divide(Xs,Ys,Zs) :-
divide(Xs,Xs,Ys,Zs).
divide(Ls,[],[],Ls).
divide([H|Ts],[_],[H],Ts).
divide([H|Ts],[_,_|Zs],[H|Us],Rs)
:- divide(Ts,Zs,Us,Rs).
The divide/4 predicate works but stripping both a single element and a double element from the initial list. By the time the second argument gets to the empty list or a list of one element then we are effectively halfway through the list passed as the first argument.
It's effectively O(n/2) complexity.
Here's a sample output:
?- divide([a,b,c,d,e,f,g,h],X,Y).
X = [a, b, c, d],
Y = [e, f, g, h] .
?- divide([a,b,c,d,e,f,g],X,Y).
X = [a, b, c, d],
Y = [e, f, g] .
Another answer,
uses Backtracking a lot, isn't very performant, though.
append and length are assumed to be predefined:
divide(A,B,C):-
append(B,C,A),
length(B,B_Length),
length(C,C_Length),
(B_Length = C_Length;
B_Length =:= C_Length +1).
Oh, sorry, just have seen that this is sort of a rephrasing of the answer from Philip Whitehouse.
This is how I did it. Almost no built-ins:
split_list_in_half( Xs , H , T ) :-
list_length( X , L ) ,
LL = L - (L // 2) ,
take_first( Xs , LL , H , T ) ,
.
list_length( L , N ) :-
list_length( L , 0 , N )
.
list_length( [] , N , N ).
list_length( [X|Xs] , T , N ) :-
T1 is T+1 ,
list_length( Xs , T1 , N )
.
take_first( Xs , N , Pfx , Sfx ) :-
take_first( Xs , N , [] , P1 , Sfx ) ,
reverse( P1 , Pfx )
.
take_first( [] , _ , H , H , [] ).
take_first( [X|Xs] , 0 , H , H , [X|Xs] ).
take_first( [X|Xs] , N , H1 , H , T ) :-
N > 0 ,
N1 = N-1 ,
take_first( Xs , N1 , [X|H1] , H , T )
.
Improved head-and-tail iteration, guarding against infinity:
split_list_half([A,B|T], Half1, Half2) :-
split_list_half_([A,B|T], [A,B|T], Half1, Half2, Half2).
split_list_half_([], H2, [], _, H2).
% H2D prevents infinity with: split_list_half(L, H1, [c, d]).
split_list_half_([_|T], [H|Sgl], H1, H2D, H2) :-
split_list_half_dbl_(T, H, Sgl, H1, H2D, H2).
split_list_half_dbl_([], H, H2, [H], _, H2).
split_list_half_dbl_([_|T], H, Sgl, [H|H1], [_|H2D], H2) :-
split_list_half_(T, Sgl, H1, H2D, H2).
Results in swi-prolog:
?- split_list_half([a,b,c,d], H1, H2).
H1 = [a, b],
H2 = [c, d].
?- split_list_half([a,b,c,d,e], H1, H2).
H1 = [a, b, c],
H2 = [d, e].
?- split_list_half(LF, H1, [d, e]).
LF = [_A, _B, d, e],
H1 = [_A, _B] ;
LF = [_A, _B, _C, d, e],
H1 = [_A, _B, _C] ;
false.