setof / 3 внутри setof / 3 не работает, но почему?

Вдохновлен

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

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

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

Хорошее решение

Проясните проблему:

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

  1. Учитывая набор фильмов MovIn
  2. ... Найдите Набор актеров ActOut
  3. ... ... Так, что: Каждый Актер в ActOut появлялся (по крайней мере) во всех фильмах в MovIn
  4. ... ... Новая формулировка: Набор фильмов MovAx для любого актера Ax из ActOut является надмножеством MovIn.

setof / 3 кажется правильным предикатом верхнего уровня. Анзац для пунктов 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).

person David Tonhofer    schedule 08.03.2020    source источник


Ответы (1)


Пытаться:

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].
person Paulo Moura    schedule 08.03.2020
comment
Что ж, это было просто. - person David Tonhofer; 08.03.2020