问题
I'm pretty new to Prolog, Don't be too hard on me. Anyhow, I've got the next problem in Prolog:
I've created a small 'database' of actors, defined by:
actor(ID, Name).
Same goes for movies,cast,Director, Defined by:
movie(ID,Name, Director, Category).
director(ID,Name).
cast(MovieID, ActorID).
Now i need to Write a procedure people(Movie, List) that defines the relation between movie name and list of names of all people participated in the movie - director and actors (in any order).
So I've started by:
people(Movie, List):-
movie(MovID,Movie,_,_,_), %Getting the movie ID.
helper(MovID,List).
% Either its a director.
helper(MovID,[Y|Ys]):-
director(DirID,Y),
movie(MovID,_,DirID,_,_),
helper(MovID,Ys).
% Or an actor
helper(MovID,[Y|Ys]):-
actor(ActID,Y),
cast(MovID,ActID),
helper(MovID,Ys).
% Finished when reached to an empty List.
helper(MovID,[]).
So what the above does is answering whether a given list is acting [or Directing] in that movie. [But it has a problem as well, Since a list which doesn't contain -all- the actors will still get 'true'.]
Anyhow, I thought a bit more about my solution, And I think that it's logically not the perfect approach to that question [That's why i didn't finish it].
I thought about trying another approach, And it's by logically asking: What do i actually need to answer about?
And the answer is: Is there a list so that appending the list of actors in the movie with the director [There's only one] equals to it.
But now I'm pretty much stuck. How can i use a self-created lists in Prolog? Getting the list of actors is easy and it's by doing:
cast(MovieID,_).
But how can i use the answer defined by the function? [Can i even do that?] Or shall i try to change my approach again?
回答1:
The relation people(Move, Persons)
is, given your database, no longer a monotonic relation. For, would you add facts to actor/2
and cast/2
, the relation people/2
would now succeed for a longer and different list of Persons.
So, given that, you can define helper/2
with setof/3
. In fact, you need setof/3
or some other non-monotonic construct to that end:
helper(MovID, Ys) :-
setof(Y, person_in(Y,MovID), Ys).
person_in(Y, MovID) :-
movie(MovID, _, DirID, _, _),
director(DirID, Y).
person_in(Y, MovID) :-
cast(MovID, ActID),
actor(ActID, Y).
Alternatively, you might put all of it into one big goal. Be aware that in such a situation all existential variables have to be declared:
helper(MovID, Ys) :-
setof(Y, Ex1^Ex2^Ex3^DirId^ActID^
( move(MovID,Ex1,DirID,Ex2,Ex3), director(DirId,Y)
; cast(MovID, ActID), actor(ActId, Y)
),
Ys).
It is very easily possible to forget a variable or two, so you might also use library(lambda) to handle such variables implicitly. This is particularly useful for anonymous variables:
helper(MovID, Ys) :-
setof(Y, {MovID,Y}+\
( move(MovID,_,DirID,_,_), director(DirId,Y)
; cast(MovID, ActID), actor(ActId, Y)
),
Ys).
回答2:
Something like this should do what you want:
% movie_people/2 ----------------------------------
%
% finds all the people involved in a given movie:
% - look up the movie
% - look up the director
% - find all the actors involved in the film
%-------------------------------------------------
movie_people( Title , [directed_by(Director)|Actors] ) :-
movie(Id,Title,DirectorId,_) ,
director(DirectorId,Director) ,
findall( actor(Name) , movie_cast(Id,Name) , Actors )
.
% movie_cast ------------------------------------------------
%
% Enumerate the actors involved in a movie via backtracking.
%
%------------------------------------------------------------
movie_cast( MovieId , Name ) :-
cast(MovieID , ActorId ) ,
actor(ActorId,Name)
.
But your model, though, with its use of [presumably numeric] IDs, doesn't seem very Prolog-ish. It has the whiff of procedural thinking.
A more typical model in Prolog might look something like this:
%----------------------------------------------------------------
% Title Actor Role
%----------------------------------------------------------------
cast( the_thin_man , william_powell , nick_charles ) .
cast( the_thin_man , myrna_loye , nora_charles ) .
cast( the_thin_man , maureen_o_sullivan , dorothy ) .
cast( the_thin_man , nat_pendleton , guild ) .
cast( the_thin_man , minna_gombell , mimi ) .
cast( the_thin_man , porter_hall , maccaulley ) .
cast( the_thin_man , henry_wadsworth , tommy ) .
cast( the_thin_man , william_henry , gilbertt ) .
cast( the_thin_man , harold_huber , nunheim ) .
cast( the_thin_man , cesar_romero , chris ) .
cast( the_thin_man , natalie_moorhead , julia_wolf ) .
cast( the_thin_man , edward_brophy , morelli ) .
cast( the_thin_man , edward_ellis , wynant ) .
cast( the_thin_man , cyril_thornton , tanner ) .
cast( wife_vs_secretary , clark_gable , van ) .
cast( wife_vs_secretary , jean_harlow , whitey ) .
cast( wife_vs_secretary , myrna_loy , linda ) .
cast( wife_vs_secretary , may_robson , mimi ) .
cast( wife_vs_secretary , george_barbier , underwood ) .
cast( wife_vs_secretary , james_stewart , dave ) .
cast( wife_vs_secretary , hobart_cavanaugh , joe ) .
cast( wife_vs_secretary , tom_dugan , finney ) .
cast( wife_vs_secretary , gilbert_emery , simpson ) .
cast( wife_vs_secretary , marjorie_gateson , eve_merritt ) .
cast( wife_vs_secretary , gloria_holden , joan_carstairs ) .
film( the_thin_man ) .
film( wife_vs_secretary ) .
category( the_thin_man , comedy ) .
category( the_thin_man , screwball_comedy ) .
category( the_thin_man , film_noir ) .
category( the_thin_man , mystery ) .
category( wife_vs_secretary , comedy ) .
category( wife_vs_secretary , drama ) .
category( wife_vs_secretary , romance ) .
directed_by( the_thin_man , w_s_van_dyke ) .
director_by( wife_vs_secretary , clarence_brown ) .
Then things become easy
An actor is someone who has been cast in a film
actor(X) :- cast(_,X,_) , ! .
A director is someone who has directed a film
director(X) :- directed_by(_,X) , ! .
Find all the films in which a given actor has acted:
films_of(X,Titles) :- findall(Title,cast(Title,X,_),Titles) .
List the people involved in a film
movie_people( Title , Director , Cast ) :- directed_by( Title , Director ) , findall(Actor,cast(Title,Actor,_),Actors) .
etc.
来源:https://stackoverflow.com/questions/24207171/using-a-self-created-list-in-prolog