Using a self-created list in prolog

那年仲夏 提交于 2019-12-24 00:46:49

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!