setof / 3 внутри setof / 3 не работает, но почему? - PullRequest
2 голосов
/ 08 марта 2020

Вдохновленный

Найти общий элемент в различных фактах в 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).

И с учетом набора фильмов найдите тех актеров, которые снялся во всех фильмах из указанного набора.

Сначала у меня было некрасивое решение, но потом ...

Решение, которое приятно

Уточнение проблемы:

Наборы представлены списками без дубликатов, возможно, упорядочены.

  1. Учитывая Набор фильмов MovIn
  2. ... Найти набор актеров ActOut
  3. ... ... такой, что: каждый актер в ActOut появился (по крайней мере) во всех фильмах в MovIn
  4. ... ... Переформулировано: Набор фильмов 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).

1 Ответ

2 голосов
/ 08 марта 2020

Попробуйте:

actors_appearing_in_movies(MovIn,ActOut) :-
    setof(
        Ax,
        MovAx^(setof(Mx,starsin(Mx,Ax),MovAx), subset(MovIn,MovAx)),
        ActOut
    ).

Без экзистенциальной квалификации переменной MovAx вы получите решение для каждой привязки переменной.

Пример вызова:

?- actors_appearing_in_movies([a,b],ActOut).
ActOut = [george, maria].
...