Search code examples
listprologinstantiation

Separate list by first occurence of variable in SWI-Prolog without instantiating the variable itself


I have following source-code:

split_list(List, L, [R1|RN], Condition) :-
   find_first(List, R1, Condition),
   append(L, [R1|RN], List), 
   forall(member(X, L),
   not(call(Condition, X))).

find_first([H|_], H, Condition) :- call(Condition, H), !.
find_first([_|T], X, Condition) :- find_first(T, X, Condition).

This Prolog program splits a list List into two lists L and [R1|RN]. R1 is the first element of List which satisfies the predicate Condition. L contains all elements in List before R1. L does not contain any element satisfying Condition. RN contains all elements which follow R1 in List.

My aim now is to write some predicate, which separates some list [a,b,c,D,d,f,e,f,d] into two lists [a, b, c] and [D, d, f, e, f, d] without instantiating the variable D.

I just tried the call:

split_list([a,b,c,_,d,f,e,f,d], L, R, var).

but this produces much solutions by instantiating _ by a or b or c and so on. How can I solve it?


Solution

  • From the looks of it, this is a more useful find_first (with argument order changed to be more sensible):

    % P means previous, R means remainder
    find_first_succ(Cond, L, P, [H|T]) :-
        find_first_succ_(L, Cond, P, [H|T]).
    
    find_first_succ_([H|T], Cond, [], [H|T]) :-
        call(Cond, H), !.
    find_first_succ_([H|T], Cond, [H|P], R) :-
        find_first_succ_(T, Cond, P, R).
    

    Result in swi-prolog:

    ?- find_first_succ(var, [a,b,c,_,d,f,e,f,d], P, R).
    P = [a, b, c],
    R = [_, d, f, e, f, d].
    

    So, you don't need that problematic append.