Вдохновлен
Найдите общий элемент в разных фактах в swi-prolog
Хотел попробовать свои силы в «Операциях с СУБД на Прологе» (собственно, это более-менее Datalog)
Постановка задачи
Учитывая базу данных «актеров, снимающихся в кино»:
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 кажется правильным предикатом верхнего уровня. Анзац для пунктов 1 и 2:
setof(Ax, (... MovIn ...) , ActOut).
Если MovAx
- это Набор фильмов, в котором появился Ax
, мы можем использовать
- subset / 2 из библиотека (списки) или
- ord_subset / 2 из library (ordset) ... если мы можем гарантировать, что evertyhing - это ordset.
Давайте использовать 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).