Вдохновленный
Найти общий элемент в различных фактах в swi-prolog
Я хотел попробовать свои силы в "Операциях СУБД в Прологе" (на самом деле это является более или менее даталогом)
Постановка задачи
С учетом базы данных "актеров, снимающихся в кино":
starsin(a,bob).
starsin(c,bob).
starsin(a,maria).
starsin(b,maria).
starsin(c,maria).
starsin(a,george).
starsin(b,george).
starsin(c,george).
starsin(d,george).
И с учетом набора фильмов найдите тех актеров, которые снялся во всех фильмах из указанного набора.
Сначала у меня было некрасивое решение, но потом ...
Решение, которое приятно
Уточнение проблемы:
Наборы представлены списками без дубликатов, возможно, упорядочены.
- Учитывая Набор фильмов
MovIn
- ... Найти набор актеров
ActOut
- ... ... такой, что: каждый актер в
ActOut
появился (по крайней мере) во всех фильмах в MovIn
- ... ... Переформулировано: Набор фильмов
MovAx
для любого актера Ax
из ActOut
является надмножеством MovIn
.
setof / 3 кажется правильным предикатом верхнего уровня. Ansatz для точек 1 и 2:
setof(Ax, (... MovIn ...) , ActOut).
Если MovAx
- это Набор фильмов , в котором появился Ax
, мы можем использовать
Давайте использовать subset/2
.
Точка 4, кажется, заставляет нас писать:
setof(Ax, (..., subset(MovAx, MovIn)) , ActOut).
Разработка ...
...
setof(Ax, ( setof(Mx,starsin(Mx,Ax),MovAx) , subset(MovIn, MovAx) ) , ActOut).
Кажется, это уже так!
Ощущение, когда есть выражения λ, но нет ни на клавиатуре, ни в синтаксисе.
Готово!
Заключение в предикат:
actors_appearing_in_movies(MovIn,ActOut) :-
setof(Ax, ( setof(Mx,starsin(Mx,Ax),MovAx) , subset(MovIn, MovAx) ) , ActOut).
К сожалению, вышеприведенное не работает.
Идет откат назад, по-видимому, я нужно обернуть все в другое setof/3
, но зачем ??
?- actors_appearing_in_movies([a,b],ActOut).
ActOut = [maria] ;
ActOut = [george].
Готово, взять два
Следующее работает :
subselect(Ax,MovIn) :-
setof(Mx,starsin(Mx,Ax),MovAx), subset(MovIn, MovAx).
actors_appearing_in_movies(MovIn,ActOut) :-
setof(Ax, subselect(Ax,MovIn) , ActOut).
?- actors_appearing_in_movies([a,b],ActOut).
ActOut = [george, maria].
Тестирование
Тестирование просто запускает несколько голов.
Обратите внимание, что для пустого набора фильмов мы получаем всех актеров. Это возможно правильно: каждый актер снимается во всех фильмах пустого набора.
actors_appearing_in_movies([],ActOut),permutation([bob, george, maria],ActOut),!.
actors_appearing_in_movies([a],ActOut),permutation([bob, george, maria],ActOut),!.
actors_appearing_in_movies([a,b],ActOut),permutation([george, maria],ActOut),!.
actors_appearing_in_movies([a,b,c],ActOut),permutation([george, maria],ActOut),!.
actors_appearing_in_movies([a,b,c,d],ActOut),permutation([george],ActOut),!.
Вопрос
Что я пропустил в
actors_appearing_in_movies(MovIn,ActOut) :-
setof(Ax, ( setof(Mx,starsin(Mx,Ax),MovAx) , subset(MovIn, MovAx) ) , ActOut).