Home > Software design >  I want to make a filtered list out of a existing list in prolog
I want to make a filtered list out of a existing list in prolog

Time:09-17

The problem is; I have a list of mixed elements [Y, donkey, horse, 30, father(max)]. I want to make a new list out of this with exclusively atoms.

I want to write a Prolog predicate called atoms/2 that, when supplied with a list in the first argument position, will instantiate the variable provided in the second argument position with the list of all atoms occurring in the inputlist (including any possible duplicate elements).

Like this:

?- atoms([Y, donkey, horse, 30, father(max)], Result).
Result = [donkey, horse].

CodePudding user response:

I'm assuming that this is for schoolwork, and that your instructor would like you to roll your own code, rather than using the in-built, member/2 and findall/3.

Prolog has an in-built predicate, atom/1, that we'll use to identify atoms.

And prolog is a recursive language. The trick is to learn to think recursively. Most recursive problems can be broken down into 1 or 2 special cases, and then the more general recursive case.

So...

We have one special case, the empty list:

atoms( [] , [] ).

and we have two general, recursive cases. One is the case where the head (1st item) of the list is an atom, which case we add the list item to the result list and recurse down:

atoms( [X|Xs], [X|Atoms] ) :- atom(X), !, atoms(Xs,Atoms) .

The other/last case is the case where the current list item is something other than an atom, in which case we simply discard the list item and recurse down.

atoms( [X|Xs],    Atoms  ) := \ atom(X), atoms(Xs,Atoms) .

Putting it all together, you get

atoms( []     , []        ) .
atoms( [X|Xs] , [X|Atoms] ) :-    atom(X), atoms(Xs,Atoms) .
atoms( [X|Xs] ,    Atoms  ) :- \  atom(X), atoms(Xs,Atoms) .

Note that this can be simplified to eliminate the redundant test for atomicity. The identification a list item as an atom is deterministics, that is, the list item isn't going to stop being an atom is we look at it again, so we can use the cut (!) operator to prune the search tree:

atoms( []     , []        ) .
atoms( [X|Xs] , [X|Atoms] ) :-    atom(X), !, atoms(Xs,Atoms) .
atoms( [X|Xs] ,    Atoms  ) :-                atoms(Xs,Atoms) .

CodePudding user response:

  1. Install SWI-Prolog.
  2. Start it.
  3. Type, on the ?- prompt: edit(include/3). and hit Enter.
  4. Marvel as you see the library definition of include/3.
  5. Use this as the starting point of your predicate.
  6. Ponder the importance of open source.

Alternatively, check out this answer: How do I make a new filtered list out of existing list in Prolog?

CodePudding user response:

As most Prolog systems implement a member/2 list membership predicate and also the standard atom/1 and findall/3 predicates, a simple portable solution is:

atoms(List, Atoms) :-
    findall(
        Atom,
        (member(Atom, List), atom(Atom)),
        Atoms
    ).

Sample call:

| ?- atoms([Y, donkey, horse, 30, father(max)], Atoms).

Atoms = [donkey,horse]

yes
  • Related