Prolog: Filter and list

2019-08-25 07:13发布

Construct a predicate called fPairsAtoms/3 so that given an atom (first argument), and a list of pairs, unify a third parameter with the filtered list of pairs by selecting only the pairs that have the first component as the atom of the first argument.

Example:

fPairsAtoms(sA,[[basA,absAb],[ab,bbsA],[sA,abbsB],[bsA,sAsB],[sA,bb]],X)  

Result:

X = [[sA,abbsB],[sA,bb]]

I do not understand ..... What should I face these types of exercises? Can you help me find a solution?

Today I started with prolog, I am a newbie in every way.

2条回答
戒情不戒烟
2楼-- · 2019-08-25 07:39

To filter the pairs in the list, you need to traverse it while comparing the given atom with the first element of each pair. A trivial predicate to traverse a list would be:

traverse([]).
traverse([Head| Tail]) :-
    traverse(Tail).

The predicate in your problem description is terribly named and don't follow recommended Prolog coding guidelines. Let's rename it to filter_pairs_by_key/3 and change the argument order to filter_pairs_by_key(Pairs, SearchKey, FilteredPairs). Also, the recommended representation for a pair in Prolog is Key-Value. There are standard predicates and library predicates that expect this representation (e.g. keysort/2). Based on the traverse/2 predicate template and the code style recommendations, we can write:

filter_pairs_by_key([], _, []).
filter_pairs_by_key([Key-Value| Pairs], SearchKey, [Key-Value| FilteredPairs]) :-
     Key = SearchKey, 
     filter_pairs_by_key(Pairs, Atom, FilteredPairs).
filter_pairs_by_key([Key-_| Pairs], SearchKey, FilteredPairs) :-
     Key \= SearchKey, 
     filter_pairs_by_key(Pairs, SearchKey, FilteredPairs).

Note that I'm using two clauses for the non-empty list case: one when the pair key matches the atom and one when the match fails.

Sample call:

| ?- filter_pairs_by_key([basA-absAb,ab-bbsA,sA-abbsB,bsA-sAsB,sA-bb], sA, FilteredPairs).          

FilteredPairs = [sA-abbsB,sA-bb] ? 

yes

More can be said about this problem and this particular solution but, as mentioned in the comments, this is not a beginners exercise. Consider the comments recommendations and after being comfortable with Prolog list notation play with this solution.

查看更多
狗以群分
3楼-- · 2019-08-25 07:59

If you've just started today, it probably is a bit too soon for you to tackle this problem.

First you should understand what Prolog terms are: atoms, logical Variables, compound terms foo(x,X,bar(baz)).

Then you should understand unification, a = a, a = A, A = a, A = foo(a), foo(A) = foo(a), [atom, B] = [A, bar].

You should understand lists representation, where

[  A,   B,   C     ] 
= [A,   B | [C]    ] 
= [A | [B ,  C    ]] 
= [A | [B | [C]   ]] 
= .... 
= [A ,  B ,  C | []] 

so that unifying [A | B] = [a] succeeds, resulting in also unifying A = a and B = [], but unifying [A | B] = [] fails.

Then you need to understand predicates, which under procedural interpretation mean,

to_prove(This) :- need_to_prove(This) , and_also(That).

So that

fPairsAtoms(sA, [[basA,absAb],[ab,bbsA],[sA,abbsB],[bsA,sAsB],[sA,bb]], X) :-
            X = [                       [sA,abbsB],           [sA,bb]].

is a perfectly valid, though exceedingly narrow, definition of one.

But then so are also

fPairsAtoms(sA, [[basA,absAb],[ab,bbsA],[sA,abbsB] | [[bsA,sAsB],[sA,bb]] ], X) :-
            X = [                       [sA,abbsB] | [           [sA,bb]] ].
% and 
fPairsAtoms(sA, [             [ab,bbsA],[sA,abbsB] | [[bsA,sAsB],[sA,bb]] ], X) :-
            X = [                       [sA,abbsB] | [           [sA,bb]] ].
% and 
fPairsAtoms(sA, [                       [sA,abbsB] | [[bsA,sAsB],[sA,bb]] ], X) :-
            X = [                       [sA,abbsB] | [           [sA,bb]] ].
% and 
fPairsAtoms(sA,                                      [[bsA,sAsB],[sA,bb]]  , Y) :-
            Y =                                      [           [sA,bb]].
% ... and 
fPairsAtoms(sA,                                                        []  , Y) :-
            Y =                                                        [].

and so also

fPairsAtoms(sA, [                       [sA,abbsB] | L                    ], X) :- 
            L =                                      [[bsA,sAsB],[sA,bb]], 
            Y =                                      [           [sA,bb]],
            X = [                       [sA,abbsB] | Y                    ].

and thus

fPairsAtoms(sA, [                       [sA,abbsB] | L                    ], X) :- 
            L =                                      [[bsA,sAsB],[sA,bb]], 
            fPairsAtoms( L, Y),
            Y =                                      [           [sA,bb]],
            X = [                       [sA,abbsB] | Y                    ].
% and
fPairsAtoms(sA, [                       [sA,abbsB] | L                    ], X) :-
            L =                                      [[bsA,sAsB],[sA,bb]], 
            fPairsAtoms( L, Y),
            X = [                       [sA,abbsB] | Y                    ].
% and
fPairsAtoms(sA, [                       [sA,abbsB] | L                    ], X) :-
            fPairsAtoms( L, Y),
            X = [                       [sA,abbsB] | Y                    ].
% and so
fPairsAtoms(sA, [                       A          | L                    ], X) :-
            A =                         [sA, B   ],
            fPairsAtoms( L, Y),
            X = [                       A          | Y                    ].
% and even
fPairsAtoms(SA, [                       A          | L                    ], X) :-
            A =                         [SA, B   ],
            fPairsAtoms( SA, L, Y),
            X = [                       A          | Y                    ].

But on the other hand, in cases were there was no match, we saw that it is

fPairsAtoms(SA, [                       A          | L                    ], X) :-
            A =                         [SB, B   ],
            dif( SA, SB),
            fPairsAtoms( SA, L, Y),
            X =                                      Y                     .
% i.e.
fPairsAtoms(SA, [                       [SB, B   ] | L                    ], X) :-
            dif( SA, SB),
            fPairsAtoms( SA, L,                      X)                    .

So which one of the two clauses, that we've ended up with,

fPairsAtoms( SA, [ [SA, _] | L ], X) :-
            fPairsAtoms( SA, L, Y),
            X = [A |            Y].

fPairsAtoms( SA, [ [SB, _] | L ], X) :-
            dif( SA, SB),
            fPairsAtoms( SA, L,   X).

is the right one? The answer is: both!

查看更多
登录 后发表回答