zaig
zaig

Reputation: 421

Prolog list of predicates to list of lists

I have a list like: [a([x,y]), b([u,v])] and I want my result as [[x,y], [u,v]]. Here is my code:

p(L, Res) :- 
    findall(X, (member(a(X), L)), A1), append([A1],[],L1),
    findall(Y, (member(b(Y), L)), A2), append(L1,[A2],L2),
    append(L2, Res).

This provides a partially good result but if my list is [a([x,y]), c([u,v])], I would like the result to be: [[x,y],[]] and it is [[x,y]].
More examples:

 p([b([u,v]), a([x,y]), c([s,t]), d([e,f])], R)

The result I get: [[x,y],[u,v]] (as expected).

p([b([u,v]), z([x,y]), c([s,t]), d([e,f])], R)

The result I get: [[u,v]]'.
The result I want: [[],[u,v]].

EDIT: Added more examples.

Upvotes: 0

Views: 592

Answers (2)

lurker
lurker

Reputation: 58324

Now that it's clear what the problem statement really is, the solution is a little more understood. Your current solution is a little bit overdone and can be simplified. Also, the case where you want to have a [] element when the term isn't found falls a little outside of the paradigm, so can be handled as an exception. @AnsPiter has the right idea about using =../2, particularly if you need a solution that handles multiple occurrences of a and/or b in the list.

p(L, Res) :-
    find_term(a, L, As),     % Find the a terms
    find_term(b, L, Bs),     % Find the b terms
    append(As, Bs, Res).     % Append the results

find_term(F, L, Terms) :-
    Term =.. [F, X],
    findall(X, member(Term, L), Ts),
    (   Ts = []              % No results?
    ->  Terms = [[]]         % yes, then list is single element, []
    ;   Terms = Ts           % no, then result is the list of terms
    ).

Usage:

| ?- p([b([u,v]), z([x,y]), c([s,t]), d([e,f])], R).

R = [[],[u,v]]

yes
| ?-  p([b([x,y]), a([u,v])], L).

L = [[u,v],[x,y]]

yes
| ?-

The above solution will handle multiple occurrences of a and b.

If the problem really is restricted to one occurrence of each, then findall/3 and append/3 are way overkill and the predicate can be written:

p(L, [A,B]) :-
    (   member(a(A), L)
    ->  true
    ;   A = []
    ),
    (   member(b(B), L)
    ->  true
    ;   B = []
    ).

Upvotes: 1

Ans Piter
Ans Piter

Reputation: 573

Term =.. List : Unifies List with a list whose head is the atom corresponding to the principal functor of Term and whose tail is a list of the arguments of Term.

Example :

| ?- foo(n,n+1,n+2)=..List.
List = [foo,n,n+1,n+2] ? 

| ?- Term=..[foo,n,n+1,n+2].
Term = foo(n,n+1,n+2)

rely on your suggestion; you have a term contains a single argument List
so ;

p([],[]).                            
p([X|Xs], Result) :-
            X=..[F,Y],
            (%IF
            \+(F='c')-> % not(F=c)            
            Result=[Y|Res]; 
            %ELSE           
            Result = Res % Result = [Res] ==> [[x,y],[]]
            ),
            p(Xs,Res). 

Test :

| ?- p([a([x,y]), c([u,v])],R).
R = [[x,y]] ? 
yes

| ?- p([a([x,y]), b([u,v])],R).
R = [[x,y],[u,v]] ? 
yes

Upvotes: 0

Related Questions