使用list而不是multiple子句来枚举数据

时间:2016-07-29 02:16:40

标签: prolog

我想制作一个Prolog程序,我有一个" Person"那"看了" "影#34 ;. 我希望像watched(person's code, [movie code 1, movie code 2])一样写它,这样我就可以为每个人写一个观看电影的列表,而不是写很多行。

我有这些movie/2事实:

% movie(code, movie's name).
movie(1, 'Thor 1').
movie(2, 'Thor 2').
movie(3, 'Captain America').
movie(4, 'Captain America 2').

这些person/2事实:

% person(code, persons's name).
person(1, 'ana').
person(2, 'john').

以及这些watched/2事实:

% watched(person's code, movie's code).
watched(1, [1,2,3]).
watched(2, [1,2,4]).

如你所见,Ana例如观看了电影“Thor 1',' Thor 2'和'美国队长'。

我试图查询以下内容:

?- watched(P, [X,Y,Z]), movie(Z,N), Z is X, Z is Y.

但是prolog不会接受它。

有没有办法将两个变量分配给一个?与Z is X, Z is Y

一样

另外,如果我查询:

(_, [ _ ,_,Z| _ ]) = (_, [1, 2, 3, 4]), movie(Z,N).

prolog将返回一部电影,但只有一部电影,而(_, [ _, _|Z])无法播放多部电影。

2 个答案:

答案 0 :(得分:1)

好的,所以您希望能够查询watched_movie('ana', 'Thor 2')形式的内容。让我们来看看所涉及的步骤。

  • 标题看起来像watched_movie(P, M) :-,其中P是人物的姓名,M是电影名称。
  • 参数是名称,但数据使用ID。因此,让我们将名称转换为ID:

    person(PId, P),    
    movie(MId, M),
    

    这将查看数据库以获取相应的ID和名称。

  • 从这些ID对中,谓词只有在此人实际观看过该电影时才会成功。为此,只需从数据库中获取观看的电影列表,并检查它是否包含电影ID。

    watched(PId, Movies),
    member(MId, Movies).
    

    member是一个内置的prolog谓词;但我鼓励你自己编写它作为练习。)

就是这样。把它们放在一起,谓词看起来像这样:

watched_movie(P, M) :-
    person(PId, P),    
    movie(MId, M),
    watched(PId, Movies),
    member(MId, Movies).

现在您可以查询所需的一切。

?- watched_movie('ana','Thor 2').
true.

?- watched_movie(P, 'Thor 2').
P = ana;
P = john.

?- watched_movie('ana', M).
P = 'Thor 1';
P = 'Thor 2';
P = 'Captain America'.

?- watched_movie(P, M).
M = 'Thor 1',
P = ana;
...

至于你的尝试:

  • watched(P, [X,Y,Z]), movie(Z,N), Z is X, Z is Y.

    在这里,您可以查询已经观看过3部电影的人(因为列表正是那么长),但是当您放置Z is X, Z is Y时,您基本上会说所有3部电影都必须相同。您的数据库中没有此类数据,因此查询失败。

  • (_, [ _ ,_,Z| _ ]) = (_, [1, 2, 3, 4]), movie(Z,N).

    虽然这是有效的prolog,但这个查询的第一部分真正做的唯一事情就是说Z == 3.第二部分得到这部电影的名称,ID为3,因为只有一部分你得到的确切结果。

答案 1 :(得分:1)

@Steven的answer涵盖了有关此问题的所有内容,但是阅读看起来像OP的评论仍然对Prolog找到的不同解决方案感到困惑:

  

"是的,但我希望在剧情时间与多部电影联系。"

     

"那么,用document.Content.Text创建数据库的唯一方法是写出很多行?所以,如果有人观看了6部电影,那就是:watched?"

似乎你想要完成的是获得给定人物的所有观看电影,而不是获得单独的答案。为此,您可以使用额外逻辑的全解决方案谓词。我们来看看它对您的代码的用途。

使用@ Steven的谓词(平凡编辑):

watched(1, 1). watched(1, 2). watched(1, 3). watched(1, 4). watched(1, 5).

我们现在只需环绕person_watched_movie(P,M) :- person(PId,P), watched(PId,MovieIds), member(MId,MovieIds), movie(MId,M). 谓词:

findall/3

现在,您可以获取某人/每个人/ ...一次观看的电影列表:

person_watched_movies(Person,Movies) :-
    findall(Movie,person_watched_movie(Person,Movie),Movies).

让我们考虑一下一般的查询,当我们要求Prolog找到任何人看过的电影时会发生什么?好吧,它应该给我们任何电影中至少观看过一次的事实 - 请注意,由于多人可以观看同一部电影,因此可能会出现重复的电影。我们来试试吧!

?- person_watched_movies('ana',M).
M = ['Thor 1', 'Thor 2', 'Captain America'].

大!接下来,我们还可以使用此谓词快速获取某些特定人员观看的电影列表:

使用析取运算符:

?- person_watched_movies(X,Y).
Y = ['Thor 1', 'Thor 2', 'Captain America', 'Thor 1', 'Thor 2', 'Captain America 2'].

或等效地,使用?- (X='ana' ; X='john'), person_watched_movies(X,Y). X = ana, Y = ['Thor 1', 'Thor 2', 'Captain America'] ; X = john, Y = ['Thor 1', 'Thor 2', 'Captain America 2']. 和列表:

member/2

最后,如果您想同时检索观看电影的人,您可以使用?- member(X,['ana','john']), person_watched_movies(X,Y). X = ana, Y = ['Thor 1', 'Thor 2', 'Captain America'] ; X = john, Y = ['Thor 1', 'Thor 2', 'Captain America 2']. 表示法,如下所示:

-/2

当给出我们之前使用的相同的一般查询时,这将改为输出:

person_watched_movies(Person,Movies) :-
    findall(Person-Movie,person_watched_movie(Person,Movie),Movies).

希望这有帮助!