Использование самосозданного списка в prolog

#prolog #prolog-setof

#prolog #prolog-setof

Вопрос:

Я довольно новичок в Prolog, не будьте слишком строги ко мне. Во всяком случае, у меня следующая проблема в Prolog:

Я создал небольшую «базу данных» участников, определенную:

 actor(ID, Name).
  

То же самое касается фильмов, актеров, режиссера, определяемых:

 movie(ID,Name, Director, Category).
director(ID,Name).
cast(MovieID, ActorID).
  

Теперь мне нужно написать процедуру people (Movie, List), которая определяет связь между названием фильма и списком имен всех людей, участвовавших в фильме — режиссера и актеров (в любом порядке).

Итак, я начал с:

 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,[]).
  

Итак, что делает приведенное выше, так это отвечает, действует ли данный список [или направляет] в этом фильме. [Но у него также есть проблема, поскольку список, который не содержит -all- актеров, все равно получит «true».]

Во всяком случае, я немного больше подумал о своем решении, и я думаю, что это логически не идеальный подход к этому вопросу [вот почему я его не закончил].

Я подумал о том, чтобы попробовать другой подход, и логично спросить: о чем мне на самом деле нужно ответить?

И ответ таков: есть ли список, чтобы добавление списка актеров в фильме с режиссером [Есть только один] равнялось ему.

Но теперь я в значительной степени застрял. Как я могу использовать самосозданные списки в Prolog? Получить список участников легко, и это делается:

   cast(MovieID,_).
  

Но как я могу использовать ответ, определенный функцией? [Могу ли я вообще это сделать?] Или мне снова попытаться изменить свой подход?

Ответ №1:

Отношение people(Move, Persons) , учитывая вашу базу данных, больше не является монотонным отношением. Для, если бы вы добавили факты в actor/2 и cast/2 , отношение people/2 теперь было бы успешным для более длинного и разного списка лиц.

Итак, учитывая это, вы можете определить helper/2 с setof/3 помощью . На самом деле, вам нужна setof/3 или какая-либо другая немонотонная конструкция для этой цели:

 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).
  

В качестве альтернативы, вы можете объединить все это в одну большую цель. Имейте в виду, что в такой ситуации должны быть объявлены все экзистенциальные переменные:

 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).
  

Очень легко можно забыть одну или две переменные, поэтому вы также можете использовать library(lambda) для обработки таких переменных неявно. Это особенно полезно для анонимных переменных:

 helper(MovID, Ys) :-
   setof(Y, {MovID,Y} 
              ( move(MovID,_,DirID,_,_), director(DirId,Y)
              ; cast(MovID, ActID), actor(ActId, Y)
              ),
         Ys).
  

Комментарии:

1. Потрясающе, вы действительно помогли мне понять.

Ответ №2:

Что-то вроде этого должно делать то, что вы хотите:

 % 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)
  .
  

Но ваша модель, тем не менее, с использованием [предположительно числовых] идентификаторов, не кажется очень прологичной. В нем есть привкус процедурного мышления.

Более типичная модель в Prolog может выглядеть примерно так:

 %----------------------------------------------------------------  
%     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 ) .
  

Тогда все становится просто

  • Актер — это тот, кто был снят в фильме

     actor(X) :- cast(_,X,_) , ! .
      
  • Режиссер — это тот, кто снял фильм

     director(X) :- directed_by(_,X) , ! .
      
  • Найдите все фильмы, в которых снимался данный актер:

     films_of(X,Titles) :-
      findall(Title,cast(Title,X,_),Titles) .
      
  • Перечислите людей, участвующих в фильме

     movie_people( Title , Director , Cast ) :-
      directed_by( Title , Director ) ,
      findall(Actor,cast(Title,Actor,_),Actors)
      .
      
  • и т.д.

Комментарии:

1. найдите все /3 и ! сделайте ваше определение очень хрупким в использовании.