0
votes

I am trying to make a code in which the input is a list with lists and non-lists within it and the output is a list with the lists from the first input. So, for example input listsFromList([2,3,6,[a,g],2,3,[c,d]],X). The output would be X = [[a,g],[c,d]]. I am trying to do it with an accumulator. So I made this code:

listsFromList([],A) :- A.

listsFromList([H|SOURCEs],A) :-
        is_list(H),
        append([A],H,A),
        listsFromList(SOURCEs,A).

listsFromList([H|SOURCEs],A) :-
        \+ is_list(H),
        listsFromList(SOURCEs,A).

It does not work if I put more than one list in the first list and also it gives a wrong output when I put one list in it. Can anyone help?

1

1 Answers

3
votes

You need to modify few things. Here a solution with the same number of arguments:

listsFromList([],[]).    
listsFromList([H|SOURCEs],[H|A1]) :-
        is_list(H),
        listsFromList(SOURCEs,A1).    
listsFromList([H|SOURCEs],A) :-
        \+ is_list(H),
        listsFromList(SOURCEs,A).

?- listsFromList([2,3,6,[a,g],2,3,[c,d]],X). 
X = [[a, g], [c, d]];
false

If you want to use append/3, you could add an accumulator list (so increase the arity form 2 to 3), but this is unnecessary, or swap the position of append/3. Furthermore, you can add a cut (!) to avoid the false solution.

Solution wiht accumulator:

listsFromList([],L,L).    
listsFromList([H|SOURCEs],LIn,LO) :-
    is_list(H),
    append([H],LIn,L),
    listsFromList(SOURCEs,L,LO).    
listsFromList([H|SOURCEs],L,LO) :-
    \+ is_list(H),
    listsFromList(SOURCEs,L,LO).

?- listsFromList([2,3,6,[a,g],2,3,[c,d]],[],X).
X = [[c, d], [a, g]]
false

If you want to use append/2 with arity 2 of the main predicate, use:

listsFromList([],[]).    
listsFromList([H|SOURCEs],L) :-
    is_list(H),
    listsFromList(SOURCEs,L1),
    append([H],L1,L).
listsFromList([H|SOURCEs],A) :-
    \+ is_list(H),
    listsFromList(SOURCEs,A).

?- listsFromList([2,3,6,[a,g],2,3,[c,d]],X).
X = [[a, g], [c, d]]
false

If you want to be super fancy and super short, you can solve your problem (assuming you are running SWI Prolog) with one line:

?- include(is_list,[2,3,6,[a,g],2,3,[c,d]],X). 
X = [[a, g], [c, d]]