简体   繁体   中英

Prolog predicate for showing each member of a list which is on an even position

I'm studying this new concept of logical programming with Prolog. I've worked with cuts, fails, and now I'm at the topic of lists. I have the following task to do: -Write a function evenmember(Element, List) , which will show if an element is at an even position in a list. For example evenmember(X,[1,5,3,2]) will show consecutively the solutions X=5,X=2 .

I've been playing around for a while and have written the following:

evenmember(_, []) :- !, fail.  
evenmember(_, [_]) :- !, fail.  
evenmember(X, [_, X]) :- !.  
evenmember(Elem, List):-  
    [_, Elem1|Tail] = List,  
    Elem is Elem1,  
    evenmember(Elem1, Tail).

The only way to show the results that worked for me was to introduce write function, but it does not work for the task. As far as I remember, we cannot use Elem and List directly, so I'm kind of confused. I ask for assistance and I'm going to be grateful for your help =)

In Prolog it often helps to think about the problem in logical natural language first, then try to translate that to Prolog.

What you are asking for is a rule evenmember( X, L ) which is true if X is an even member of L . If we can properly define this rule, the solutions will be each even member of L . So expressing in natural language:

1) X is an even member of L if X is the second element of L.

So I'll state that in Prolog:

evenmember(X, [_, X|_]).   % The 2nd member of a 2-element list is an even member

That only describes the first even member. The remaining even members can be described recursively:

2) X is an even member of L if X is an even member of the tail of L
   ignoring the first two elements.

Translate this into Prolog and see what you get. This one doesn't need a cut, either. You have to be conservative with cuts. They mean that you want to prune the search tree. In this case that would mean you could stop seeking valid solutions (finding all the even members).

Note that the description I'm giving assumes you want to get a single (the next, more specifically) even member of the list on each call to the predicate, rather than the entire even list at once, since that's what the original description indicates.

Here's a solution:

%% evenmembers(+List, -ListOfEvenPlacedMembers).
%    true when ListOfEvenPlacedMembers is a list of the elements of List at even places.
% 
1| evenmembers([],[]).
2| evenmembers([_Odd], []).
3| evenmembers([_Odd,Even|List], [Even|Evens]) :-
4|    evenmembers(List, Evens).

Here's a translation of the lines:

  1. The even members of an empty list is an empty list (there are none).
  2. The even members of a list with one element is an empty list (again, there are none).
  3. The even members of a list with the first two elements _Odd, and Even, and the rest List, is a list whose first member is [Even] and whose subsequent members are Evens IF
  4. the even members of List are Evens.

The rule at line 4 picks off the first two elements of a list and puts the second, even placed, element into the list of evenly placed elements. If you're running this in the swi-prolog interpreter, it should give you the solutions without you having to use write/1 . However, if you wanted to use an io predicate to format the output, you can do so by adding a helper predicate:

format_evenmembers(List) :-
    evenmember(List, Evens),
    format("Even members are ~w", [Evens]).

This looks like homework, but I'll point you in the right direction by showing a similar example.

even_members([], []).
even_members([_], []) :- !.
even_members([_,Even|Tail], [Even|Result]) :-
  even_members(Tail, Result).

which gives

?- even_members([1,5,3,2], X).
X = [5, 2].

We take the 2nd element in the head of the list (which will always be the evenly positioned element), and add it to the list which will contain the answer. Then recursively iterate through the list using the tail.

The base case is when we reach the end of the list. Since we traverse the list 2 elements at a time, for an even length list we'll reach an empty list, and for an odd length list there'll be a single element left (as pointed out by aBathologist). Once we reach a base case, we build the list going back up the recursion tree.

My example stores the answer in a list, which is typically what you'd want (lists are common in Prolog). In your solution, you don't want to store the results in a list.

PS It's been over a year since I wrote any Prolog, so hopefully I still know what I'm talking about.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM