Peach
Peach

Reputation: 13

Searching for names in list - Sicstus Prolog

I've recently started messing round with Prolog but have hit a stumbling block with lists.

Let's say I have a list [dom,is,a,man,jane,is,a,woman,mary,is,a,woman] and I want to create a new list of womans names [jane,mary]. How would I go about doing this? I assume I'd have to search through the list for any X that is followed by is,a,woman but I have no idea how to achieve this. I've been googling for hours to no avail. I would post code if I had any :s

Thanks for your help!

Upvotes: 1

Views: 131

Answers (2)

Kijewski
Kijewski

Reputation: 26022

% end once the input is empty
find_gender([], _, []).

% Compare the first 4 "entries" in the list.
% Name and Gender are variables, b/c they are written in upper case.
% 'is' and 'a' are atom.
% If the pattern matches, prepend the Name to the results.
find_gender([Name,is,a,Gender|Tail], Gender, [Name|Names]) :-
    % Find further Names in the Tail of the input list.
    find_gender(Tail, Gender, Names).

% The person is not of that Gender.
% You don't need to catch the Name here, b/c it won't be used. 
find_gender([_,is,a,X|Tail], Gender, Names) :-
    X \= Gender, % otherwise you would have wrong results when backtracking
    find_gender(Tail, Gender, Names).

% This is your usage example:
find_women(List, Names) :-
    find_gender(List, woman, Names).
find_men(List, Names) :-
    find_gender(List, man, Names).

The reverse works as well:

?- find_women(List, [jane,marry]).
List = [jane, is, a, woman, marry, is, a, woman] ;
false.

If your input list could contain other data, as in [jane,owns,a,car,jane,is,a,woman,the,car,is,red], then you could simply drop entries until you find your pattern again by adding this clause:

find_gender([_|T], Gender, Names) :-
    find_gender(T, Gender, Names).

But this will cause you to have multiple results when backtracking, with some names omitted. You might want to introduce cuts (!) in the first clauses in that case.

Upvotes: 1

mat
mat

Reputation: 40768

As always when describing lists, consider using DCGs. For example:

men_women([], [])     --> [].
men_women(Ms, [W|Ws]) --> [W,is,a,woman], men_women(Ms, Ws).
men_women([M|Ms], Ws) --> [M,is,a,man], men_women(Ms, Ws).

Example query and its result:

?- phrase(men_women(_, Ws), [dom,is,a,man,jane,is,a,woman,mary,is,a,woman]).
Ws = [jane, mary] ;
false.

This DCG also works for very general queries, such as:

?- length(Ls, _), phrase(men_women(_, Ws), Ls).
Ls = [], Ws = [] ;
Ls = [_G376, is, a, woman], Ws = [_G376] ;
Ls = [_G376, is, a, man], Ws = [] ;
Ls = [_G376, is, a, woman, _G388, is, a, woman], Ws = [_G376, _G388] .

Upvotes: 2

Related Questions