0
votes

I'm trying to work on this Prolog rule you pass in an input of a list of movies and it returns a list of a star that are involved in that particular movie.

Predicate:

starsin(captain_america,chris_evan).
starsin(avengers,chris_evan).
starsin(ant_man,chris_evan).
starsin(captain_marvel,chris_evan).
starsin(iron_man,chris_evan).
starsin(avengers,tom_holland).
starsin(captain_marvel,tom_holland).
starsin(captain_america,tom_holland).
starsin(iron_man,robert).
starsin(avengers,robert).
starsin(captain_america,robert).

I tried to use set of rule but somehow I cant figure out a way to use it recursively:

link([Head],Set) :-
   setof(Star1,starsin(Head,Star1),Set).

Input and Output:

link([ironman],Set).
Set=[chris_evan,robert]

Somehow I want to pass in more than one element in the list but I need to use recursive.

Is there anyway I could do it?

2
What happens if you have more than one movie? Does your link predicate give the set of people who are in all of them movies, or do they just need to be in one of them? - Edmund
so what I want is the input is the list of the movies and output will the list of stars that appears in that given movie for example the input: [ captain_america, avengers , ant_man ] the output would be [chris_evan] - Jack Puthichak

2 Answers

1
votes

You have a non-deterministic predicate starsin(X, Y) iff movie X includes film star Y.

Let's generalise this to tell us which stars appear in any of a list of movies.

movies_starsin(Movies, Star) :-
    member(Movie, Movies),
    starsin(Movie, Star).

Finally you want something like this:

movies_stars(Movies, Stars) :-
    setof(Star, movies_starsin(Movies, Star), Stars).

Hope this helps.

[UPDATE]

I had misunderstood the problem, which is to find the set of stars that appear in all movies in the given list. Okay:

starsin_all([Movie | Movies], Star) :-
    % Star must appear in Movie.
    starsin(Movie, Star),
    % There can be no OtherMovie in which Star does not appear.
    \+ (
        member(OtherMovie, Movies),
        \+ starsin(OtherMovie, Star)
    ).

all_starsin_all(Movies, Stars) :-
    setof(Star, starsin_all(Movies, Star), Stars).

You could equivalently write starsin_all like this:

starsin_all([Movie | Movies], Star) :-
    starsin(Movie, Star),
    forall(member(OtherMovie, Movies), starsin(OtherMovie, Star)).

Cheers.

0
votes

You probably want something like maplist/2, which can be used find solution that work with all of the members of a list, which is what you want. And then, because you want all the stars, maybe something like findall/3.

I'd advise changing starsin to put the actor first though, for two reasons: 1. It makes more sense to say "Chris Evan stars in Iron Man" than the other way round. E.g. Compare with, member(X, S) means "X is a member of S". 2. It'll work easier with maplist.

Not going to give you the full solution, because this looks a bit homeworky. :)