1

The prolog code is:

find_in_list(Element,List,Count):-
    findall(X,(member(X,List),X=Element),Output),
    length(Output,Count).

split_list([],_,_).
split_list([H|T],ListAtL1,ListAtL2):-
    split_list(T,NewListAtL1,ListAtL2),
    not(member(H,ListAtL1)),
    append(H,ListAtL1,NewListAtL1),
    find_in_list(H,[H|T],Count),
    Count is 1.
split_list([H|T],ListAtL1,ListAtL2):-
    split_list(T,NewListAtL1,NewListAtL2),
    not(member(H,ListAtL1)),
    not(member(H,ListAtL2)),
    append(H,ListAtL1,NewListAtL1),
    append(H,ListAtL2,NewListAtL2),
    find_in_list(H,[H|T],Count),
    Count is 2.

and the result is:

?- split_list([a,a,1,2,3,1,3],ListAtL1,ListAtL2).
false.

But it should be:

?- split_list([a,a,1,2,3,1,3],ListAtL1,ListAtL2).
ListAtL1=[a,1,2,3],
ListAtL2=[a,1,3].

Why this happens?

false
  • 10,264
  • 13
  • 101
  • 209

2 Answers2

1

The second and third argument aren't bound in:

?- split_list([], L1, L2).
   true.

And split_list/3 fails for:

?- split_list([A], L1, L2).
   false.
?- split_list([0], L1, L2).
   false.

You can use this technique to generalize split_list/3 (even though split_list/3 isn't pure):

split_list([],_,_).
split_list([H|T],ListAtL1,ListAtL2) :-
    * split_list(T,NewListAtL1,ListAtL2),
    not(member(H,ListAtL1)),
    * append(H,ListAtL1,NewListAtL1),
    * find_in_list(H,[H|T],Count),
    * Count is 1.
split_list([H|T],ListAtL1,ListAtL2):-
    * split_list(T,NewListAtL1,NewListAtL2),
    not(member(H,ListAtL1)),
    * not(member(H,ListAtL2)),
    * append(H,ListAtL1,NewListAtL1),
    * append(H,ListAtL2,NewListAtL2),
    * find_in_list(H,[H|T],Count),
    * Count is 2.

And split_list/3 still fails:

?- split_list([0], L1, L2).
   false.

The issue is in what remains.

false
  • 10,264
  • 13
  • 101
  • 209
notoria
  • 2,053
  • 1
  • 4
  • 15
  • Note that `not(member(H,L))` does not permit generalization prior to it. The best is to replace this by a pure `nonmember/2` – false Sep 01 '22 at 17:16
  • I edited but I can't strike the first goal of each. – notoria Sep 01 '22 at 19:36
  • Why? You have prefixed it with a `*`, so why not? – false Sep 02 '22 at 05:29
  • I'm having this [issue](https://meta.stackexchange.com/questions/126236/im-getting-your-post-appears-to-contain-code-that-is-not-properly-formatted-as) but with the code. – notoria Sep 02 '22 at 05:47
0

This is reasonably performant and also general:

:- use_module(library(reif)).

list_count_1_2([], [], []).
list_count_1_2([H|T], Lst1, Lst2) :-
    selectd_t(H, T, Sel, Bool),
    list_count_1_2_bool(Bool, T, H, Sel, Lst1, Lst2).

list_count_1_2_bool(true, _T, H, Sel, Lst1, Lst) :-
    selectd_t(H, Sel, Sel1, Bool),
    list_count_1_2_bool2(Bool, Sel, H, Sel1, Lst1, Lst).
list_count_1_2_bool(false, T, H, _Sel, Lst1, Lst2) :-
    list_count_1_2_1_(H, T, Lst1, Lst2).

list_count_1_2_bool2(true, _Sel, H, Sel1, Lst1, Lst2) :-
    % More than 2 found - remove
    exclude(==(H), Sel1, Sel2),
    list_count_1_2(Sel2, Lst1, Lst2).
list_count_1_2_bool2(false, Sel, H, _Sel1, Lst1, Lst2) :-
    list_count_1_2_2_(H, Sel, Lst1, Lst2).

list_count_1_2_1_(H, T, [H|Lst1], Lst2) :-
    list_count_1_2(T, Lst1, Lst2).

list_count_1_2_2_(H, T, [H|Lst1], [H|Lst2]) :-
    list_count_1_2(T, Lst1, Lst2).

% https://stackoverflow.com/a/44069529/
selectd_t(E, Xs0, Xs, T) :-
    i_selectd_t(Xs0, Xs, E, T).

i_selectd_t([], [], _, false).
i_selectd_t([X|Xs], Rest, E, T) :-
    if_(X = E,
        (T = true, Rest = Xs),
        (Rest = [X|Rs], i_selectd_t(Xs, Rs, E, T))
    ).

Result in swi-prolog:

?- list_count_1_2([a,X,b,c,b,c,c], L1, L2).
X = a,
L1 = L2, L2 = [a,b] ;

X = b,
L1 = [a],
L2 = [] ;

X = c,
L1 = [a,b],
L2 = [b] ;

L1 = [a,X,b],
L2 = [b],
dif(X,a),
dif(X,c),
dif(X,b).
brebs
  • 3,462
  • 2
  • 3
  • 12