#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 и ! сделайте ваше определение очень хрупким в использовании.